Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Unified Diff: media/filters/chunk_demuxer.cc

Issue 10558011: Fix ChunkDemuxer so it properly outputs buffered ranges. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address more CR comments and added an end of stream test case. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/chunk_demuxer.cc
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 1c875906ac7798b3022f0c51527c67911f9c4852..32d029af2b6cd8c673d410b1b4a3cbe8e98d88f9 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -15,6 +15,8 @@
#include "media/mp4/mp4_stream_parser.h"
#include "media/webm/webm_stream_parser.h"
+using base::TimeDelta;
+
namespace media {
struct CodecInfo {
@@ -73,6 +75,13 @@ static const SupportedTypeInfo kSupportedTypeInfo[] = {
{ "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
};
+
+// The fake total size we use for converting times to bytes
+// for AddBufferedByteRange() calls.
+// TODO(acolwell): Remove this once Pipeline accepts buffered times
+// instead of only buffered bytes.
+enum { kFakeTotalBytes = 1000000 };
+
// Checks to see if the specified |type| and |codecs| list are supported.
// Returns true if |type| and all codecs listed in |codecs| are supported.
// |factory_function| contains a function that can build a StreamParser
@@ -147,7 +156,7 @@ class ChunkDemuxerStream : public DemuxerStream {
explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config);
void StartWaitingForSeek();
- void Seek(base::TimeDelta time);
+ void Seek(TimeDelta time);
bool IsSeekPending() const;
void Flush();
@@ -157,11 +166,11 @@ class ChunkDemuxerStream : public DemuxerStream {
bool Append(const StreamParser::BufferQueue& buffers);
// Returns a list of the buffered time ranges.
- SourceBufferStream::TimespanList GetBufferedTime() const;
+ Ranges<TimeDelta> GetBufferedTime() 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(base::TimeDelta start_timestamp);
+ void OnNewMediaSegment(TimeDelta start_timestamp);
// Called when mid-stream config updates occur.
// Returns true if the new config is accepted.
@@ -212,7 +221,7 @@ class ChunkDemuxerStream : public DemuxerStream {
// The timestamp of the current media segment being parsed by
// |stream_parser_|.
- base::TimeDelta media_segment_start_time_;
+ TimeDelta media_segment_start_time_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
};
@@ -244,7 +253,7 @@ void ChunkDemuxerStream::StartWaitingForSeek() {
it->Run(NULL);
}
-void ChunkDemuxerStream::Seek(base::TimeDelta time) {
+void ChunkDemuxerStream::Seek(TimeDelta time) {
base::AutoLock auto_lock(lock_);
DCHECK(read_cbs_.empty());
@@ -264,7 +273,7 @@ void ChunkDemuxerStream::Flush() {
media_segment_start_time_ = kNoTimestamp();
}
-void ChunkDemuxerStream::OnNewMediaSegment(base::TimeDelta start_timestamp) {
+void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) {
media_segment_start_time_ = start_timestamp;
}
@@ -290,7 +299,7 @@ bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
return true;
}
-SourceBufferStream::TimespanList ChunkDemuxerStream::GetBufferedTime() const {
+Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedTime() const {
base::AutoLock auto_lock(lock_);
return stream_->GetBufferedTime();
}
@@ -463,8 +472,7 @@ void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) {
ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
: state_(WAITING_FOR_INIT),
host_(NULL),
- client_(client),
- buffered_bytes_(0) {
+ client_(client) {
DCHECK(client);
}
@@ -489,7 +497,7 @@ void ChunkDemuxer::Stop(const base::Closure& callback) {
callback.Run();
}
-void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
+void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) {
DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
PipelineStatus status = PIPELINE_ERROR_INVALID_STATE;
@@ -538,11 +546,11 @@ scoped_refptr<DemuxerStream> ChunkDemuxer::GetStream(
return NULL;
}
-base::TimeDelta ChunkDemuxer::GetStartTime() const {
+TimeDelta ChunkDemuxer::GetStartTime() const {
DVLOG(1) << "GetStartTime()";
// TODO(acolwell) : Fix this so it uses the time on the first packet.
// (crbug.com/132815)
- return base::TimeDelta();
+ return TimeDelta();
}
void ChunkDemuxer::StartWaitingForSeek() {
@@ -627,99 +635,55 @@ void ChunkDemuxer::RemoveId(const std::string& id) {
video_->Shutdown();
}
-bool ChunkDemuxer::GetBufferedRanges(const std::string& id,
- Ranges* ranges_out) const {
+Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
DCHECK(!id.empty());
DCHECK_GT(stream_parser_map_.count(id), 0u);
DCHECK(id == source_id_audio_ || id == source_id_video_);
- DCHECK(ranges_out);
base::AutoLock auto_lock(lock_);
if (id == source_id_audio_ && id != source_id_video_) {
// Only include ranges that have been buffered in |audio_|
- return CopyIntoRanges(audio_->GetBufferedTime(), ranges_out);
+ return audio_->GetBufferedTime();
}
if (id != source_id_audio_ && id == source_id_video_) {
// Only include ranges that have been buffered in |video_|
- return CopyIntoRanges(video_->GetBufferedTime(), ranges_out);
+ return video_->GetBufferedTime();
}
- // Include ranges that have been buffered in both |audio_| and |video_|.
- SourceBufferStream::TimespanList audio_ranges = audio_->GetBufferedTime();
- SourceBufferStream::TimespanList video_ranges = video_->GetBufferedTime();
- SourceBufferStream::TimespanList::const_iterator video_ranges_itr =
- video_ranges.begin();
- SourceBufferStream::TimespanList::const_iterator audio_ranges_itr =
- audio_ranges.begin();
- bool success = false;
-
- while (audio_ranges_itr != audio_ranges.end() &&
- video_ranges_itr != video_ranges.end()) {
- // If this is the last range and EndOfStream() was called (i.e. all data
- // has been appended), choose the max end point of the ranges.
- bool last_range_after_ended =
- state_ == ENDED &&
- (audio_ranges_itr + 1) == audio_ranges.end() &&
- (video_ranges_itr + 1) == video_ranges.end();
-
- // Audio range start time is within the video range.
- if ((*audio_ranges_itr).first >= (*video_ranges_itr).first &&
- (*audio_ranges_itr).first <= (*video_ranges_itr).second) {
- AddIntersectionRange(*audio_ranges_itr, *video_ranges_itr,
- last_range_after_ended, ranges_out);
- audio_ranges_itr++;
- success = true;
- continue;
- }
+ return ComputeIntersection();
+}
- // Video range start time is within the audio range.
- if ((*video_ranges_itr).first >= (*audio_ranges_itr).first &&
- (*video_ranges_itr).first <= (*audio_ranges_itr).second) {
- AddIntersectionRange(*video_ranges_itr, *audio_ranges_itr,
- last_range_after_ended, ranges_out);
- video_ranges_itr++;
- success = true;
- continue;
- }
+Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const {
+ lock_.AssertAcquired();
- // No overlap was found. Increment the earliest one and keep looking.
- if ((*audio_ranges_itr).first < (*video_ranges_itr).first)
- audio_ranges_itr++;
- else
- video_ranges_itr++;
- }
+ if (!audio_ || !video_)
+ return Ranges<TimeDelta>();
- return success;
-}
-
-bool ChunkDemuxer::CopyIntoRanges(
- const SourceBufferStream::TimespanList& timespans,
- Ranges* ranges_out) const {
- for (SourceBufferStream::TimespanList::const_iterator itr = timespans.begin();
- itr != timespans.end(); ++itr) {
- ranges_out->push_back(*itr);
+ // Include ranges that have been buffered in both |audio_| and |video_|.
+ Ranges<TimeDelta> audio_ranges = audio_->GetBufferedTime();
+ Ranges<TimeDelta> video_ranges = video_->GetBufferedTime();
+ Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges);
+
+ if (state_ == ENDED && result.size() > 0) {
+ // If appending has ended, extend the last intersection range to include the
+ // max end time of the last audio/video range. This allows the buffered
+ // information to match the actual time range that will get played out if
+ // the streams have slightly different lengths.
+ TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1);
+ TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1);
+ TimeDelta video_start = video_ranges.start(video_ranges.size() - 1);
+ TimeDelta video_end = video_ranges.end(video_ranges.size() - 1);
+
+ // Verify the last audio range overlaps with the last video range.
+ // This is enforced by the logic that controls the transition to ENDED.
+ DCHECK((audio_start <= video_start && video_start <= audio_end) ||
+ (video_start <= audio_start && audio_start <= video_end));
+ result.Add(result.end(result.size()-1), std::max(audio_end, video_end));
}
- return !timespans.empty();
-}
-
-void ChunkDemuxer::AddIntersectionRange(
- SourceBufferStream::Timespan timespan_a,
- SourceBufferStream::Timespan timespan_b,
- bool last_range_after_ended,
- Ranges* ranges_out) const {
- base::TimeDelta start = timespan_a.first;
-
- // If this is the last range after EndOfStream() was called, choose the later
- // end point of the ranges, otherwise choose the earlier.
- base::TimeDelta end;
- if (last_range_after_ended)
- end = std::max(timespan_a.second, timespan_b.second);
- else
- end = std::min(timespan_a.second, timespan_b.second);
- ranges_out->push_back(std::make_pair(start, end));
+ return result;
}
bool ChunkDemuxer::AppendData(const std::string& id,
@@ -731,7 +695,7 @@ bool ChunkDemuxer::AppendData(const std::string& id,
DCHECK(data);
DCHECK_GT(length, 0u);
- int64 buffered_bytes = 0;
+ Ranges<TimeDelta> ranges;
PipelineStatusCB cb;
{
@@ -772,13 +736,26 @@ bool ChunkDemuxer::AppendData(const std::string& id,
std::swap(cb, seek_cb_);
}
- buffered_bytes_ += length;
- buffered_bytes = buffered_bytes_;
+ if (duration_ > TimeDelta() && duration_ != kInfiniteDuration()) {
+ if (audio_ && !video_) {
+ ranges = audio_->GetBufferedTime();
+ } else if (!audio_ && video_) {
+ ranges = video_->GetBufferedTime();
+ } else {
+ ranges = ComputeIntersection();
+ }
+ }
}
- // Notify the host of 'network activity' because we got data, using a bogus
- // range.
- host_->AddBufferedByteRange(0, buffered_bytes);
+ DCHECK(!ranges.size() || duration_ > TimeDelta());
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ // Notify the host of 'network activity' because we got data.
+ int64 start =
+ kFakeTotalBytes * ranges.start(i).InSecondsF() / duration_.InSecondsF();
+ int64 end =
+ kFakeTotalBytes * ranges.end(i).InSecondsF() / duration_.InSecondsF();
+ host_->AddBufferedByteRange(start, end);
+ }
if (!cb.is_null())
cb.Run(PIPELINE_OK);
@@ -821,10 +798,10 @@ bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
if (video_)
video_->EndOfStream();
- ChangeState_Locked(ENDED);
-
if (status != PIPELINE_OK)
ReportError_Locked(status);
+ else
+ ChangeState_Locked(ENDED);
return true;
}
@@ -928,8 +905,7 @@ bool ChunkDemuxer::CanEndOfStream_Locked() const {
(!video_ || video_->CanEndOfStream());
}
-void ChunkDemuxer::OnStreamParserInitDone(bool success,
- base::TimeDelta duration) {
+void ChunkDemuxer::OnStreamParserInitDone(bool success, TimeDelta duration) {
DVLOG(1) << "OnSourceBufferInitDone(" << success << ", "
<< duration.InSecondsF() << ")";
lock_.AssertAcquired();
@@ -947,6 +923,8 @@ void ChunkDemuxer::OnStreamParserInitDone(bool success,
(!source_id_video_.empty() && !video_))
return;
+ if (duration_ > TimeDelta() && duration_ != kInfiniteDuration())
+ host_->SetTotalBytes(kFakeTotalBytes);
host_->SetDuration(duration_);
ChangeState_Locked(INITIALIZED);
@@ -1024,7 +1002,7 @@ bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data,
}
void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id,
- base::TimeDelta start_timestamp) {
+ TimeDelta start_timestamp) {
// TODO(vrk): There should be a special case for the first appends where all
// streams (for both demuxed and muxed case) begin at the earliest stream
// timestamp. (crbug.com/132815)
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698