memory_limit_(kDefaultAudioMemoryLimit),
config_change_pending_(false),
splice_buffers_index_(0),
+ pre_splice_complete_(false),
splice_frames_enabled_(splice_frames_enabled) {
DCHECK(audio_config.IsValidConfig());
audio_configs_.push_back(audio_config);
memory_limit_(kDefaultVideoMemoryLimit),
config_change_pending_(false),
splice_buffers_index_(0),
+ pre_splice_complete_(false),
splice_frames_enabled_(splice_frames_enabled) {
DCHECK(video_config.IsValidConfig());
video_configs_.push_back(video_config);
memory_limit_(kDefaultAudioMemoryLimit),
config_change_pending_(false),
splice_buffers_index_(0),
+ pre_splice_complete_(false),
splice_frames_enabled_(splice_frames_enabled) {}
SourceBufferStream::~SourceBufferStream() {
DCHECK(!buffers.empty());
DCHECK(media_segment_start_time_ != kNoTimestamp());
+ DCHECK(media_segment_start_time_ <= buffers.front()->GetDecodeTimestamp());
DCHECK(!end_of_stream_);
// New media segments must begin with a keyframe.
last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
last_appended_buffer_is_keyframe_ = buffers.back()->IsKeyframe();
} else {
- base::TimeDelta new_range_start_time = media_segment_start_time_;
+ base::TimeDelta new_range_start_time = std::min(
+ media_segment_start_time_, buffers.front()->GetDecodeTimestamp());
const BufferQueue* buffers_for_new_range = &buffers;
BufferQueue trimmed_buffers;
last_output_buffer_timestamp_ = kNoTimestamp();
splice_buffers_index_ = 0;
splice_buffer_ = NULL;
+ pre_splice_complete_ = false;
}
bool SourceBufferStream::ShouldSeekToStartOfBuffered(
// timestamp situation. This prevents the first buffer in the current append
// from deleting the last buffer in the previous append if both buffers
// have the same timestamp.
- bool is_exclusive = (prev_timestamp == next_timestamp) &&
+ //
+ // The delete range should never be exclusive if a splice frame was generated
+ // because we don't generate splice frames for same timestamp situations.
+ DCHECK(new_buffers.front()->splice_timestamp() !=
+ new_buffers.front()->timestamp());
+ const bool is_exclusive =
+ new_buffers.front()->get_splice_buffers().empty() &&
+ prev_timestamp == next_timestamp &&
AllowSameTimestamp(prev_is_keyframe, next_is_keyframe, GetType());
// Delete the buffers that |new_buffers| overlaps.
return SourceBufferStream::kConfigChange;
}
+ // Every pre splice buffer must have the same splice_timestamp().
+ DCHECK(splice_buffer_->splice_timestamp() ==
+ splice_buffers[splice_buffers_index_]->splice_timestamp());
+
*out_buffer = splice_buffers[splice_buffers_index_++];
return SourceBufferStream::kSuccess;
}
// Did we hand out the last pre-splice buffer on the previous call?
- if (splice_buffers_index_ == last_splice_buffer_index) {
- splice_buffers_index_++;
+ if (!pre_splice_complete_) {
+ DCHECK_EQ(splice_buffers_index_, last_splice_buffer_index);
+ pre_splice_complete_ = true;
config_change_pending_ = true;
DVLOG(1) << "Config change (forced for fade in of splice frame).";
return SourceBufferStream::kConfigChange;
// so hand out the final buffer for fade in. Because a config change is
// always issued prior to handing out this buffer, any changes in config id
// have been inherently handled.
- DCHECK_GE(splice_buffers_index_, splice_buffers.size());
+ DCHECK(pre_splice_complete_);
+ DCHECK_EQ(splice_buffers_index_, splice_buffers.size() - 1);
+ DCHECK(splice_buffers.back()->splice_timestamp() == kNoTimestamp());
*out_buffer = splice_buffers.back();
splice_buffer_ = NULL;
splice_buffers_index_ = 0;
+ pre_splice_complete_ = false;
return SourceBufferStream::kSuccess;
}
DCHECK(audio_configs_.empty());
DVLOG(3) << "UpdateVideoConfig.";
- if (video_configs_[0].is_encrypted() != config.is_encrypted()) {
- MEDIA_LOG(log_cb_) << "Video Encryption changes not allowed.";
- return false;
- }
-
if (video_configs_[0].codec() != config.codec()) {
MEDIA_LOG(log_cb_) << "Video codec changes not allowed.";
return false;
// If there are gaps in the timeline, it's possible that we only find buffers
// after the splice point but within the splice range. For simplicity, we do
// not generate splice frames in this case.
- if (pre_splice_buffers.front()->timestamp() > splice_timestamp)
+ //
+ // We also do not want to generate splices if the first new buffer replaces an
+ // existing buffer exactly.
+ if (pre_splice_buffers.front()->timestamp() >= splice_timestamp)
return;
- // Sanitize |pre_splice_buffers| so that there are no recursive splices.
+ // If any |pre_splice_buffers| are already splices, do not generate a splice.
for (size_t i = 0; i < pre_splice_buffers.size(); ++i) {
const BufferQueue& original_splice_buffers =
pre_splice_buffers[i]->get_splice_buffers();
- if (original_splice_buffers.empty())
- continue;
-
- // Remove the original splice and move our index back to compensate. NOTE:
- // |i| will underflow if the splice is the first buffer, this is okay. It
- // will be corrected below or on the next loop iteration.
- pre_splice_buffers.erase(pre_splice_buffers.begin() + i--);
-
- // Cull all buffers which start after the end of the new splice point or
- // after original overlapping buffer; this may introduce gaps, but no more
- // than Remove() does currently.
- const scoped_refptr<StreamParserBuffer>& overlapping_buffer =
- original_splice_buffers.back();
- for (BufferQueue::const_iterator it = original_splice_buffers.begin();
- it != original_splice_buffers.end();
- ++it) {
- const scoped_refptr<StreamParserBuffer>& buffer = *it;
- if (buffer->timestamp() <= max_splice_end_timestamp &&
- (buffer->timestamp() < overlapping_buffer->timestamp() ||
- buffer == overlapping_buffer)) {
- // Add the buffer and adjust the index forward to compensate.
- pre_splice_buffers.insert(pre_splice_buffers.begin() + ++i, buffer);
- }
+ if (!original_splice_buffers.empty()) {
+ DVLOG(1) << "Can't generate splice: overlapped buffers contain a "
+ "pre-existing splice.";
+ return;
}
}
+ // Don't generate splice frames which represent less than two frames, since we
+ // need at least that much to generate a crossfade. Per the spec, make this
+ // check using the sample rate of the overlapping buffers.
+ const base::TimeDelta splice_duration =
+ pre_splice_buffers.back()->timestamp() +
+ pre_splice_buffers.back()->duration() - splice_timestamp;
+ const base::TimeDelta minimum_splice_duration = base::TimeDelta::FromSecondsD(
+ 2.0 / audio_configs_[append_config_index_].samples_per_second());
+ if (splice_duration < minimum_splice_duration) {
+ DVLOG(1) << "Can't generate splice: not enough samples for crossfade; have "
+ << splice_duration.InMicroseconds() << " us, but need "
+ << minimum_splice_duration.InMicroseconds() << " us.";
+ return;
+ }
+
new_buffers.front()->ConvertToSpliceBuffer(pre_splice_buffers);
}
void SourceBufferRange::AppendBuffersToEnd(const BufferQueue& new_buffers) {
DCHECK(buffers_.empty() || CanAppendBuffersToEnd(new_buffers));
+ DCHECK(media_segment_start_time_ == kNoTimestamp() ||
+ media_segment_start_time_ <=
+ new_buffers.front()->GetDecodeTimestamp());
for (BufferQueue::const_iterator itr = new_buffers.begin();
- itr != new_buffers.end(); ++itr) {
+ itr != new_buffers.end();
+ ++itr) {
DCHECK((*itr)->GetDecodeTimestamp() != kNoTimestamp());
buffers_.push_back(*itr);
size_in_bytes_ += (*itr)->data_size();