summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorvrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-02 21:24:38 +0000
committervrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-02 21:24:38 +0000
commit29dcc87a4d431025a5c8a6a4b5498172804cc9f9 (patch)
tree628c31d4be98e8a26e6530a74d0f6ccceeb45976 /media
parenta9d31ef4508af244599ae096be8e33c6bfec029b (diff)
downloadchromium_src-29dcc87a4d431025a5c8a6a4b5498172804cc9f9.zip
chromium_src-29dcc87a4d431025a5c8a6a4b5498172804cc9f9.tar.gz
chromium_src-29dcc87a4d431025a5c8a6a4b5498172804cc9f9.tar.bz2
Cap sourceBuffered() on duration and truncate duration on EoS
Adds logic + test to truncate the duration on Media Source streams when EndOfStream is signalled. Also adds some logic to make sure buffered streams never exceed the reported duration. BUG=139899 Review URL: https://chromiumcodereview.appspot.com/10829108 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149702 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/demuxer_stream.h3
-rw-r--r--media/base/ranges.h4
-rw-r--r--media/filters/chunk_demuxer.cc61
-rw-r--r--media/filters/chunk_demuxer.h7
-rw-r--r--media/filters/chunk_demuxer_unittest.cc51
-rw-r--r--media/filters/dummy_demuxer.cc4
-rw-r--r--media/filters/dummy_demuxer.h1
-rw-r--r--media/filters/ffmpeg_demuxer.cc16
-rw-r--r--media/filters/ffmpeg_demuxer.h9
9 files changed, 116 insertions, 40 deletions
diff --git a/media/base/demuxer_stream.h b/media/base/demuxer_stream.h
index 65457c3..30ef1ec 100644
--- a/media/base/demuxer_stream.h
+++ b/media/base/demuxer_stream.h
@@ -64,9 +64,6 @@ class MEDIA_EXPORT DemuxerStream
// if type() != VIDEO.
virtual const VideoDecoderConfig& video_decoder_config() = 0;
- // Returns time ranges known to have been seen by this stream.
- virtual Ranges<base::TimeDelta> GetBufferedRanges() = 0;
-
// Returns the type of stream.
virtual Type type() = 0;
diff --git a/media/base/ranges.h b/media/base/ranges.h
index 82bf7a0..f42b34a 100644
--- a/media/base/ranges.h
+++ b/media/base/ranges.h
@@ -39,7 +39,7 @@ class Ranges {
void clear();
// Computes the intersection between this range and |other|.
- Ranges<T> IntersectionWith(const Ranges<T>& other);
+ Ranges<T> IntersectionWith(const Ranges<T>& other) const;
private:
// Wrapper around DCHECK_LT allowing comparisons of operator<<'able T's.
@@ -133,7 +133,7 @@ void Ranges<T>::clear() {
}
template<class T>
-Ranges<T> Ranges<T>::IntersectionWith(const Ranges<T>& other) {
+Ranges<T> Ranges<T>::IntersectionWith(const Ranges<T>& other) const {
Ranges<T> result;
size_t i = 0;
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index b1c2389..e866da3d 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -176,6 +176,9 @@ class ChunkDemuxerStream : public DemuxerStream {
// Returns true if buffers were successfully added.
bool Append(const StreamParser::BufferQueue& buffers);
+ // Returns the range of buffered data in this stream, capped at |duration|.
+ Ranges<TimeDelta> GetBufferedRanges(base::TimeDelta duration) const;
+
// Signal to the stream that buffers handed in through subsequent calls to
// Append() belong to a media segment that starts at |start_timestamp|.
void OnNewMediaSegment(TimeDelta start_timestamp);
@@ -199,7 +202,6 @@ class ChunkDemuxerStream : public DemuxerStream {
virtual void EnableBitstreamConverter() OVERRIDE;
virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
- virtual Ranges<TimeDelta> GetBufferedRanges() OVERRIDE;
protected:
virtual ~ChunkDemuxerStream();
@@ -318,9 +320,20 @@ bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
return true;
}
-Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges() {
+Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
+ base::TimeDelta duration) const {
base::AutoLock auto_lock(lock_);
- return stream_->GetBufferedTime();
+ Ranges<TimeDelta> range = stream_->GetBufferedTime();
+
+ if (range.size() == 0u)
+ return range;
+
+ // Clamp the end of the stream's buffered ranges to fit within the duration.
+ // This can be done by intersecting the stream's range with the valid time
+ // range.
+ Ranges<TimeDelta> valid_time_range;
+ valid_time_range.Add(range.start(0), duration);
+ return range.IntersectionWith(valid_time_range);
}
bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) {
@@ -671,12 +684,12 @@ Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
if (id == source_id_audio_ && id != source_id_video_) {
// Only include ranges that have been buffered in |audio_|
- return audio_ ? audio_->GetBufferedRanges() : Ranges<TimeDelta>();
+ return audio_ ? audio_->GetBufferedRanges(duration_) : Ranges<TimeDelta>();
}
if (id != source_id_audio_ && id == source_id_video_) {
// Only include ranges that have been buffered in |video_|
- return video_ ? video_->GetBufferedRanges() : Ranges<TimeDelta>();
+ return video_ ? video_->GetBufferedRanges(duration_) : Ranges<TimeDelta>();
}
return ComputeIntersection();
@@ -689,8 +702,8 @@ Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const {
return Ranges<TimeDelta>();
// Include ranges that have been buffered in both |audio_| and |video_|.
- Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges();
- Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges();
+ Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges(duration_);
+ Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges(duration_);
Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges);
if (state_ == ENDED && result.size() > 0) {
@@ -763,13 +776,7 @@ bool ChunkDemuxer::AppendData(const std::string& id,
std::swap(cb, seek_cb_);
}
- if (audio_ && !video_) {
- ranges = audio_->GetBufferedRanges();
- } else if (!audio_ && video_) {
- ranges = video_->GetBufferedRanges();
- } else {
- ranges = ComputeIntersection();
- }
+ ranges = GetBufferedRanges();
}
for (size_t i = 0; i < ranges.size(); ++i)
@@ -825,10 +832,12 @@ bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
if (video_)
video_->EndOfStream();
- if (status != PIPELINE_OK)
+ if (status != PIPELINE_OK) {
ReportError_Locked(status);
- else
+ } else {
ChangeState_Locked(ENDED);
+ DecreaseDurationIfNecessary();
+ }
return true;
}
@@ -1121,7 +1130,7 @@ void ChunkDemuxer::IncreaseDurationIfNecessary(
if (buffers.back()->GetTimestamp() <= duration_)
return;
- Ranges<TimeDelta> ranges = stream->GetBufferedRanges();
+ Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration());
DCHECK_GT(ranges.size(), 0u);
base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1);
@@ -1129,4 +1138,22 @@ void ChunkDemuxer::IncreaseDurationIfNecessary(
UpdateDuration(last_timestamp_buffered);
}
+void ChunkDemuxer::DecreaseDurationIfNecessary() {
+ Ranges<TimeDelta> ranges = GetBufferedRanges();
+ if (ranges.size() == 0u)
+ return;
+
+ base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1);
+ if (last_timestamp_buffered < duration_)
+ UpdateDuration(last_timestamp_buffered);
+}
+
+Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
+ if (audio_ && !video_)
+ return audio_->GetBufferedRanges(duration_);
+ else if (!audio_ && video_)
+ return video_->GetBufferedRanges(duration_);
+ return ComputeIntersection();
+}
+
} // namespace media
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index fb53bca..fe8e671 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -143,9 +143,16 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
const StreamParser::BufferQueue& buffers,
const scoped_refptr<ChunkDemuxerStream>& stream);
+ // Decreases |duration_| if the buffered region is less than |duration_| when
+ // EndOfStream() is called.
+ void DecreaseDurationIfNecessary();
+
// Sets |duration_| to |new_duration| and notifies |host_|.
void UpdateDuration(base::TimeDelta new_duration);
+ // Returns the ranges representing the buffered data in the demuxer.
+ Ranges<base::TimeDelta> GetBufferedRanges() const;
+
mutable base::Lock lock_;
State state_;
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 1570bea..71ebe9a 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -47,6 +47,8 @@ static const int kVideoBlockDuration = 33;
static const char* kSourceId = "SourceId";
static const char* kDefaultFirstClusterRange = "{ [0,46) }";
+static const int kDefaultFirstClusterEndTimestamp = 66;
+static const int kDefaultSecondClusterEndTimestamp = 132;
base::TimeDelta kDefaultDuration() {
return base::TimeDelta::FromMilliseconds(201224);
@@ -1100,6 +1102,8 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWithPendingReads) {
end_of_stream_helper_1.CheckIfReadDonesWereCalled(false);
end_of_stream_helper_2.CheckIfReadDonesWereCalled(false);
+ EXPECT_CALL(host_, SetDuration(
+ base::TimeDelta::FromMilliseconds(kVideoBlockDuration)));
demuxer_->EndOfStream(PIPELINE_OK);
end_of_stream_helper_1.CheckIfReadDonesWereCalled(true);
@@ -1139,6 +1143,8 @@ TEST_F(ChunkDemuxerTest, TestReadsAfterEndOfStream) {
EXPECT_TRUE(video_read_done_1);
end_of_stream_helper_1.CheckIfReadDonesWereCalled(false);
+ EXPECT_CALL(host_, SetDuration(
+ base::TimeDelta::FromMilliseconds(kVideoBlockDuration)));
EXPECT_TRUE(demuxer_->EndOfStream(PIPELINE_OK));
end_of_stream_helper_1.CheckIfReadDonesWereCalled(true);
@@ -1697,6 +1703,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_EndOfStream) {
CheckExpectedRanges("{ [0,90) }");
+ EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(100)));
demuxer_->EndOfStream(PIPELINE_OK);
CheckExpectedRanges("{ [0,100) }");
@@ -1813,6 +1820,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamFailures) {
// Make sure that end of stream fails because there is a gap between
// the current position(0) and the end of the appended data.
+ EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(50)));
ASSERT_FALSE(demuxer_->EndOfStream(PIPELINE_OK));
// Seek to an time that is inside the last ranges for both streams
@@ -1863,6 +1871,8 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamDuringSeek) {
demuxer_->StartWaitingForSeek();
ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size()));
+ EXPECT_CALL(host_, SetDuration(
+ base::TimeDelta::FromMilliseconds(kDefaultSecondClusterEndTimestamp)));
demuxer_->EndOfStream(PIPELINE_OK);
demuxer_->Seek(base::TimeDelta::FromSeconds(0),
@@ -2133,20 +2143,36 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetMidParse) {
TEST_F(ChunkDemuxerTest, TestDurationChange) {
ASSERT_TRUE(InitDemuxer(true, true, false));
+ static const int kStreamDuration = kDefaultDuration().InMilliseconds();
// Add data leading up to the currently set duration.
scoped_ptr<Cluster> first_cluster = GenerateCluster(
- kDefaultDuration().InMilliseconds() - kAudioBlockDuration,
- kDefaultDuration().InMilliseconds() - kVideoBlockDuration, 2);
+ kStreamDuration - kAudioBlockDuration,
+ kStreamDuration - kVideoBlockDuration, 2);
ASSERT_TRUE(AppendData(first_cluster->data(), first_cluster->size()));
- // Now add data past the duration and expect a new duration to be signalled.
+ CheckExpectedRanges(kSourceId, "{ [201191,201224) }");
+
+ // Add data at the currently set duration. The duration should not increase.
scoped_ptr<Cluster> second_cluster = GenerateCluster(
- kDefaultDuration().InMilliseconds(), 4);
- EXPECT_CALL(host_, SetDuration(
- kDefaultDuration() + base::TimeDelta::FromMilliseconds(
- kAudioBlockDuration * 2)));
+ kDefaultDuration().InMilliseconds(), 2);
ASSERT_TRUE(AppendData(second_cluster->data(), second_cluster->size()));
+
+ // Range should not be affected.
+ CheckExpectedRanges(kSourceId, "{ [201191,201224) }");
+
+ // Now add data past the duration and expect a new duration to be signalled.
+ static const int kNewStreamDuration =
+ kStreamDuration + kAudioBlockDuration * 2;
+ scoped_ptr<Cluster> third_cluster = GenerateCluster(
+ kStreamDuration + kAudioBlockDuration,
+ kStreamDuration + kVideoBlockDuration, 2);
+ EXPECT_CALL(host_, SetDuration(
+ base::TimeDelta::FromMilliseconds(kNewStreamDuration)));
+ ASSERT_TRUE(AppendData(third_cluster->data(), third_cluster->size()));
+
+ // See that the range has increased appropriately.
+ CheckExpectedRanges(kSourceId, "{ [201191,201270) }");
}
TEST_F(ChunkDemuxerTest, TestDurationChangeTimestampOffset) {
@@ -2162,4 +2188,15 @@ TEST_F(ChunkDemuxerTest, TestDurationChangeTimestampOffset) {
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
}
+TEST_F(ChunkDemuxerTest, TestEndOfStreamTruncateDuration) {
+ ASSERT_TRUE(InitDemuxer(true, true, false));
+
+ scoped_ptr<Cluster> cluster_a(kDefaultFirstCluster());
+ ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size()));
+
+ EXPECT_CALL(host_, SetDuration(
+ base::TimeDelta::FromMilliseconds(kDefaultFirstClusterEndTimestamp)));
+ demuxer_->EndOfStream(PIPELINE_OK);
+}
+
} // namespace media
diff --git a/media/filters/dummy_demuxer.cc b/media/filters/dummy_demuxer.cc
index 317b543..bbfcff2 100644
--- a/media/filters/dummy_demuxer.cc
+++ b/media/filters/dummy_demuxer.cc
@@ -32,10 +32,6 @@ void DummyDemuxerStream::Read(const ReadCB& read_cb) {}
void DummyDemuxerStream::EnableBitstreamConverter() {}
-Ranges<base::TimeDelta> DummyDemuxerStream::GetBufferedRanges() {
- return Ranges<base::TimeDelta>();
-}
-
DummyDemuxer::DummyDemuxer(bool has_video, bool has_audio) {
streams_.resize(DemuxerStream::NUM_TYPES);
if (has_audio)
diff --git a/media/filters/dummy_demuxer.h b/media/filters/dummy_demuxer.h
index c8c1b5e..700cd84 100644
--- a/media/filters/dummy_demuxer.h
+++ b/media/filters/dummy_demuxer.h
@@ -28,7 +28,6 @@ class DummyDemuxerStream : public DemuxerStream {
virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
virtual void EnableBitstreamConverter() OVERRIDE;
- virtual Ranges<base::TimeDelta> GetBufferedRanges() OVERRIDE;
protected:
virtual ~DummyDemuxerStream();
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index cb6494a..35c2d38 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -237,7 +237,7 @@ base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const {
return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts);
}
-Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() {
+Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const {
base::AutoLock auto_lock(lock_);
return buffered_ranges_;
}
@@ -323,7 +323,12 @@ void FFmpegDemuxer::Initialize(DemuxerHost* host,
scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(
DemuxerStream::Type type) {
- StreamVector::iterator iter;
+ return GetFFmpegStream(type);
+}
+
+scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream(
+ DemuxerStream::Type type) const {
+ StreamVector::const_iterator iter;
for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
if (*iter && (*iter)->type() == type) {
return *iter;
@@ -717,9 +722,10 @@ void FFmpegDemuxer::SignalReadCompleted(int size) {
void FFmpegDemuxer::NotifyBufferingChanged() {
DCHECK_EQ(MessageLoop::current(), message_loop_);
Ranges<base::TimeDelta> buffered;
- scoped_refptr<DemuxerStream> audio =
- audio_disabled_ ? NULL : GetStream(DemuxerStream::AUDIO);
- scoped_refptr<DemuxerStream> video = GetStream(DemuxerStream::VIDEO);
+ scoped_refptr<FFmpegDemuxerStream> audio =
+ audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO);
+ scoped_refptr<FFmpegDemuxerStream> video =
+ GetFFmpegStream(DemuxerStream::VIDEO);
if (audio && video) {
buffered = audio->GetBufferedRanges().IntersectionWith(
video->GetBufferedRanges());
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index b90cbbb..f395a84 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -84,7 +84,9 @@ class FFmpegDemuxerStream : public DemuxerStream {
virtual void EnableBitstreamConverter() OVERRIDE;
virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
- virtual Ranges<base::TimeDelta> GetBufferedRanges() OVERRIDE;
+
+ // Returns the range of buffered data in this stream.
+ Ranges<base::TimeDelta> GetBufferedRanges() const;
// Returns elapsed time based on the already queued packets.
// Used to determine stream duration when it's not known ahead of time.
@@ -210,6 +212,11 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol {
// read or kReadError in case of error.
virtual void SignalReadCompleted(int size);
+ // Returns the stream from |streams_| that matches |type| as an
+ // FFmpegDemuxerStream.
+ scoped_refptr<FFmpegDemuxerStream> GetFFmpegStream(
+ DemuxerStream::Type type) const;
+
DemuxerHost* host_;
MessageLoop* message_loop_;