Index: media/filters/source_buffer_stream.cc |
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc |
index 015fc6c610d180822a466a255babdc4bf9797f45..2ffbb6abb140eaabe0f5d9d2c920623d8db24577 100644 |
--- a/media/filters/source_buffer_stream.cc |
+++ b/media/filters/source_buffer_stream.cc |
@@ -9,6 +9,7 @@ |
#include "base/bind.h" |
#include "base/logging.h" |
+#include "base/stl_util.h" |
namespace media { |
@@ -93,6 +94,10 @@ class SourceBufferRange { |
bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); |
bool HasNextBuffer() const; |
+ // Returns the config ID for the buffer that will be returned by |
+ // GetNextBuffer(). |
+ int GetNextConfigId() const; |
+ |
// Returns true if the range knows the position of the next buffer it should |
// return, i.e. it has been Seek()ed. This does not necessarily mean that it |
// has the next buffer yet. |
@@ -229,7 +234,11 @@ static int kDefaultBufferDurationInMs = 125; |
namespace media { |
SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) |
- : stream_start_time_(kNoTimestamp()), |
+ : current_config_index_(0), |
+ append_config_index_(0), |
+ audio_configs_(1), |
+ video_configs_(0), |
+ stream_start_time_(kNoTimestamp()), |
seek_pending_(false), |
seek_buffer_timestamp_(kNoTimestamp()), |
selected_range_(NULL), |
@@ -238,11 +247,16 @@ SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) |
new_media_segment_(false), |
last_buffer_timestamp_(kNoTimestamp()), |
max_interbuffer_distance_(kNoTimestamp()) { |
- audio_config_.CopyFrom(audio_config); |
+ audio_configs_[0] = new AudioDecoderConfig(); |
+ audio_configs_[0]->CopyFrom(audio_config); |
} |
SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) |
- : stream_start_time_(kNoTimestamp()), |
+ : current_config_index_(0), |
+ append_config_index_(0), |
+ audio_configs_(0), |
+ video_configs_(1), |
+ stream_start_time_(kNoTimestamp()), |
seek_pending_(false), |
seek_buffer_timestamp_(kNoTimestamp()), |
selected_range_(NULL), |
@@ -251,7 +265,8 @@ SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) |
new_media_segment_(false), |
last_buffer_timestamp_(kNoTimestamp()), |
max_interbuffer_distance_(kNoTimestamp()) { |
- video_config_.CopyFrom(video_config); |
+ video_configs_[0] = new VideoDecoderConfig(); |
+ video_configs_[0]->CopyFrom(video_config); |
} |
SourceBufferStream::~SourceBufferStream() { |
@@ -259,6 +274,9 @@ SourceBufferStream::~SourceBufferStream() { |
delete ranges_.front(); |
ranges_.pop_front(); |
} |
+ |
+ STLDeleteElements(&audio_configs_); |
+ STLDeleteElements(&video_configs_); |
} |
void SourceBufferStream::OnNewMediaSegment( |
@@ -305,6 +323,7 @@ bool SourceBufferStream::Append( |
} |
UpdateMaxInterbufferDistance(buffers); |
+ SetConfigIds(buffers); |
// Save a snapshot of stream state before range modifications are made. |
base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp(); |
@@ -423,6 +442,13 @@ void SourceBufferStream::UpdateMaxInterbufferDistance( |
} |
} |
+void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { |
+ for (BufferQueue::const_iterator itr = buffers.begin(); |
+ itr != buffers.end(); ++itr) { |
+ (*itr)->SetConfigId(append_config_index_); |
+ } |
+} |
+ |
void SourceBufferStream::InsertIntoExistingRange( |
const RangeList::iterator& range_for_new_buffers_itr, |
const BufferQueue& new_buffers, |
@@ -653,15 +679,25 @@ bool SourceBufferStream::IsSeekPending() const { |
return seek_pending_; |
} |
-bool SourceBufferStream::GetNextBuffer( |
+SourceBufferStream::Status SourceBufferStream::GetNextBuffer( |
scoped_refptr<StreamParserBuffer>* out_buffer) { |
if (!track_buffer_.empty()) { |
+ if (track_buffer_.front()->GetConfigId() != current_config_index_) |
+ return kConfigChange; |
+ |
*out_buffer = track_buffer_.front(); |
track_buffer_.pop_front(); |
- return true; |
+ return kSuccess; |
} |
- return selected_range_ && selected_range_->GetNextBuffer(out_buffer); |
+ if (!selected_range_ || !selected_range_->HasNextBuffer()) |
+ return kNeedBuffer; |
+ |
+ if (selected_range_->GetNextConfigId() != current_config_index_) |
+ return kConfigChange; |
+ |
+ CHECK(selected_range_->GetNextBuffer(out_buffer)); |
+ return kSuccess; |
} |
base::TimeDelta SourceBufferStream::GetNextBufferTimestamp() { |
@@ -729,12 +765,99 @@ bool SourceBufferStream::IsEndSelected() const { |
return ranges_.empty() || selected_range_ == ranges_.back(); |
} |
+const AudioDecoderConfig& SourceBufferStream::GetCurrentAudioDecoderConfig() { |
+ CompleteConfigChange(); |
+ return *audio_configs_[current_config_index_]; |
+} |
+ |
+const VideoDecoderConfig& SourceBufferStream::GetCurrentVideoDecoderConfig() { |
+ CompleteConfigChange(); |
+ return *video_configs_[current_config_index_]; |
+} |
+ |
base::TimeDelta SourceBufferStream::GetMaxInterbufferDistance() const { |
if (max_interbuffer_distance_ == kNoTimestamp()) |
return base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs); |
return max_interbuffer_distance_; |
} |
+bool SourceBufferStream::UpdateAudioConfig(const AudioDecoderConfig& config) { |
+ DCHECK(!audio_configs_.empty()); |
+ DCHECK(video_configs_.empty()); |
+ |
+ if (audio_configs_[0]->codec() != config.codec()) { |
+ DVLOG(1) << "UpdateAudioConfig() : Codec changes not allowed."; |
+ return false; |
+ } |
+ |
+ if (audio_configs_[0]->samples_per_second() != config.samples_per_second()) { |
+ DVLOG(1) << "UpdateAudioConfig() : Sample rate changes not allowed."; |
+ return false; |
+ } |
+ |
+ if (audio_configs_[0]->channel_layout() != config.channel_layout()) { |
+ DVLOG(1) << "UpdateAudioConfig() : Channel layout changes not allowed."; |
+ return false; |
+ } |
+ |
+ if (audio_configs_[0]->bits_per_channel() != config.bits_per_channel()) { |
+ DVLOG(1) << "UpdateAudioConfig() : Bits per channel changes not allowed."; |
+ return false; |
+ } |
+ |
+ // Check to see if the new config matches an existing one. |
+ for (size_t i = 0; i < audio_configs_.size(); ++i) { |
+ if (config.Matches(*audio_configs_[i])) { |
+ append_config_index_ = i; |
+ return true; |
+ } |
+ } |
+ |
+ // No matches found so let's add this one to the list. |
+ append_config_index_ = audio_configs_.size(); |
+ audio_configs_.resize(audio_configs_.size() + 1); |
+ audio_configs_[append_config_index_] = new AudioDecoderConfig(); |
+ audio_configs_[append_config_index_]->CopyFrom(config); |
+ return true; |
+} |
+ |
+bool SourceBufferStream::UpdateVideoConfig(const VideoDecoderConfig& config) { |
+ DCHECK(!video_configs_.empty()); |
+ DCHECK(audio_configs_.empty()); |
+ |
+ if (video_configs_[0]->codec() != config.codec()) { |
+ DVLOG(1) << "UpdateVideoConfig() : Codec changes not allowed."; |
+ return false; |
+ } |
+ |
+ // Check to see if the new config matches an existing one. |
+ for (size_t i = 0; i < video_configs_.size(); ++i) { |
+ if (config.Matches(*video_configs_[i])) { |
+ append_config_index_ = i; |
+ return true; |
+ } |
+ } |
+ |
+ // No matches found so let's add this one to the list. |
+ append_config_index_ = video_configs_.size(); |
+ video_configs_.resize(video_configs_.size() + 1); |
+ video_configs_[append_config_index_] = new VideoDecoderConfig(); |
+ video_configs_[append_config_index_]->CopyFrom(config); |
+ return true; |
+} |
+ |
+void SourceBufferStream::CompleteConfigChange() { |
+ if (!track_buffer_.empty()) { |
+ current_config_index_ = track_buffer_.front()->GetConfigId(); |
+ return; |
+ } |
+ |
+ if (!selected_range_ || !selected_range_->HasNextBuffer()) |
+ return; |
+ |
+ current_config_index_ = selected_range_->GetNextConfigId(); |
+} |
+ |
SourceBufferRange::SourceBufferRange( |
const BufferQueue& new_buffers, base::TimeDelta media_segment_start_time, |
const InterbufferDistanceCB& interbuffer_distance_cb) |
@@ -925,12 +1048,9 @@ bool SourceBufferRange::TruncateAt( |
bool SourceBufferRange::GetNextBuffer( |
scoped_refptr<StreamParserBuffer>* out_buffer) { |
- if (waiting_for_keyframe_ || |
- next_buffer_index_ >= static_cast<int>(buffers_.size())) { |
+ if (!HasNextBuffer()) |
return false; |
- } |
- DCHECK_GE(next_buffer_index_, 0); |
*out_buffer = buffers_.at(next_buffer_index_); |
next_buffer_index_++; |
return true; |
@@ -938,9 +1058,16 @@ bool SourceBufferRange::GetNextBuffer( |
bool SourceBufferRange::HasNextBuffer() const { |
return next_buffer_index_ >= 0 && |
- next_buffer_index_ < static_cast<int>(buffers_.size()); |
+ next_buffer_index_ < static_cast<int>(buffers_.size()) && |
+ !waiting_for_keyframe_; |
} |
+int SourceBufferRange::GetNextConfigId() const { |
+ DCHECK(HasNextBuffer()); |
+ return buffers_.at(next_buffer_index_)->GetConfigId(); |
+} |
+ |
+ |
base::TimeDelta SourceBufferRange::GetNextTimestamp() const { |
DCHECK(!buffers_.empty()); |
DCHECK(HasNextBufferPosition()); |