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

Side by Side Diff: media/filters/source_buffer_stream.cc

Issue 125543002: Add plumbing and support for crossfading StreamParserBuffers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments. Created 6 years, 11 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/source_buffer_stream.h" 5 #include "media/filters/source_buffer_stream.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 10 matching lines...) Expand all
21 // Returns true if |prev_is_keyframe| and |current_is_keyframe| indicate a 21 // Returns true if |prev_is_keyframe| and |current_is_keyframe| indicate a
22 // same timestamp situation that is allowed. False is returned otherwise. 22 // same timestamp situation that is allowed. False is returned otherwise.
23 static bool AllowSameTimestamp( 23 static bool AllowSameTimestamp(
24 bool prev_is_keyframe, bool current_is_keyframe, bool is_video) { 24 bool prev_is_keyframe, bool current_is_keyframe, bool is_video) {
25 if (is_video) 25 if (is_video)
26 return !prev_is_keyframe && !current_is_keyframe; 26 return !prev_is_keyframe && !current_is_keyframe;
27 27
28 return prev_is_keyframe || !current_is_keyframe; 28 return prev_is_keyframe || !current_is_keyframe;
29 } 29 }
30 30
31 // Returns the config ID of |buffer| if |buffer| has no fade out preroll or
32 // |index| is out of range. Otherwise returns the config ID for the fade out
33 // preroll buffer at position |index|.
34 static int GetConfigId(StreamParserBuffer* buffer, size_t index) {
35 return index < buffer->GetFadeOutPreroll().size()
36 ? buffer->GetFadeOutPreroll()[index]->GetConfigId()
37 : buffer->GetConfigId();
38 }
39
31 // Helper class representing a range of buffered data. All buffers in a 40 // Helper class representing a range of buffered data. All buffers in a
32 // SourceBufferRange are ordered sequentially in presentation order with no 41 // SourceBufferRange are ordered sequentially in presentation order with no
33 // gaps. 42 // gaps.
34 class SourceBufferRange { 43 class SourceBufferRange {
35 public: 44 public:
36 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 45 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
37 46
38 // Returns the maximum distance in time between any buffer seen in this 47 // Returns the maximum distance in time between any buffer seen in this
39 // stream. Used to estimate the duration of a buffer if its duration is not 48 // stream. Used to estimate the duration of a buffer if its duration is not
40 // known. 49 // known.
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 seek_buffer_timestamp_(kNoTimestamp()), 343 seek_buffer_timestamp_(kNoTimestamp()),
335 selected_range_(NULL), 344 selected_range_(NULL),
336 media_segment_start_time_(kNoTimestamp()), 345 media_segment_start_time_(kNoTimestamp()),
337 range_for_next_append_(ranges_.end()), 346 range_for_next_append_(ranges_.end()),
338 new_media_segment_(false), 347 new_media_segment_(false),
339 last_appended_buffer_timestamp_(kNoTimestamp()), 348 last_appended_buffer_timestamp_(kNoTimestamp()),
340 last_appended_buffer_is_keyframe_(false), 349 last_appended_buffer_is_keyframe_(false),
341 last_output_buffer_timestamp_(kNoTimestamp()), 350 last_output_buffer_timestamp_(kNoTimestamp()),
342 max_interbuffer_distance_(kNoTimestamp()), 351 max_interbuffer_distance_(kNoTimestamp()),
343 memory_limit_(kDefaultAudioMemoryLimit), 352 memory_limit_(kDefaultAudioMemoryLimit),
344 config_change_pending_(false) { 353 config_change_pending_(false),
354 fade_out_preroll_index_(0) {
345 DCHECK(audio_config.IsValidConfig()); 355 DCHECK(audio_config.IsValidConfig());
346 audio_configs_.push_back(audio_config); 356 audio_configs_.push_back(audio_config);
347 } 357 }
348 358
349 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, 359 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
350 const LogCB& log_cb) 360 const LogCB& log_cb)
351 : log_cb_(log_cb), 361 : log_cb_(log_cb),
352 current_config_index_(0), 362 current_config_index_(0),
353 append_config_index_(0), 363 append_config_index_(0),
354 seek_pending_(false), 364 seek_pending_(false),
355 end_of_stream_(false), 365 end_of_stream_(false),
356 seek_buffer_timestamp_(kNoTimestamp()), 366 seek_buffer_timestamp_(kNoTimestamp()),
357 selected_range_(NULL), 367 selected_range_(NULL),
358 media_segment_start_time_(kNoTimestamp()), 368 media_segment_start_time_(kNoTimestamp()),
359 range_for_next_append_(ranges_.end()), 369 range_for_next_append_(ranges_.end()),
360 new_media_segment_(false), 370 new_media_segment_(false),
361 last_appended_buffer_timestamp_(kNoTimestamp()), 371 last_appended_buffer_timestamp_(kNoTimestamp()),
362 last_appended_buffer_is_keyframe_(false), 372 last_appended_buffer_is_keyframe_(false),
363 last_output_buffer_timestamp_(kNoTimestamp()), 373 last_output_buffer_timestamp_(kNoTimestamp()),
364 max_interbuffer_distance_(kNoTimestamp()), 374 max_interbuffer_distance_(kNoTimestamp()),
365 memory_limit_(kDefaultVideoMemoryLimit), 375 memory_limit_(kDefaultVideoMemoryLimit),
366 config_change_pending_(false) { 376 config_change_pending_(false),
377 fade_out_preroll_index_(0) {
367 DCHECK(video_config.IsValidConfig()); 378 DCHECK(video_config.IsValidConfig());
368 video_configs_.push_back(video_config); 379 video_configs_.push_back(video_config);
369 } 380 }
370 381
371 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, 382 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
372 const LogCB& log_cb) 383 const LogCB& log_cb)
373 : log_cb_(log_cb), 384 : log_cb_(log_cb),
374 current_config_index_(0), 385 current_config_index_(0),
375 append_config_index_(0), 386 append_config_index_(0),
376 text_track_config_(text_config), 387 text_track_config_(text_config),
377 seek_pending_(false), 388 seek_pending_(false),
378 end_of_stream_(false), 389 end_of_stream_(false),
379 seek_buffer_timestamp_(kNoTimestamp()), 390 seek_buffer_timestamp_(kNoTimestamp()),
380 selected_range_(NULL), 391 selected_range_(NULL),
381 media_segment_start_time_(kNoTimestamp()), 392 media_segment_start_time_(kNoTimestamp()),
382 range_for_next_append_(ranges_.end()), 393 range_for_next_append_(ranges_.end()),
383 new_media_segment_(false), 394 new_media_segment_(false),
384 last_appended_buffer_timestamp_(kNoTimestamp()), 395 last_appended_buffer_timestamp_(kNoTimestamp()),
385 last_appended_buffer_is_keyframe_(false), 396 last_appended_buffer_is_keyframe_(false),
386 last_output_buffer_timestamp_(kNoTimestamp()), 397 last_output_buffer_timestamp_(kNoTimestamp()),
387 max_interbuffer_distance_(kNoTimestamp()), 398 max_interbuffer_distance_(kNoTimestamp()),
388 memory_limit_(kDefaultAudioMemoryLimit), 399 memory_limit_(kDefaultAudioMemoryLimit),
389 config_change_pending_(false) { 400 config_change_pending_(false),
401 fade_out_preroll_index_(0) {
390 } 402 }
391 403
392 SourceBufferStream::~SourceBufferStream() { 404 SourceBufferStream::~SourceBufferStream() {
393 while (!ranges_.empty()) { 405 while (!ranges_.empty()) {
394 delete ranges_.front(); 406 delete ranges_.front();
395 ranges_.pop_front(); 407 ranges_.pop_front();
396 } 408 }
397 } 409 }
398 410
399 void SourceBufferStream::OnNewMediaSegment( 411 void SourceBufferStream::OnNewMediaSegment(
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 DCHECK(IsRangeListSorted(ranges_)); 675 DCHECK(IsRangeListSorted(ranges_));
664 DCHECK(OnlySelectedRangeIsSeeked()); 676 DCHECK(OnlySelectedRangeIsSeeked());
665 DVLOG(1) << __FUNCTION__ << " : done"; 677 DVLOG(1) << __FUNCTION__ << " : done";
666 } 678 }
667 679
668 void SourceBufferStream::ResetSeekState() { 680 void SourceBufferStream::ResetSeekState() {
669 SetSelectedRange(NULL); 681 SetSelectedRange(NULL);
670 track_buffer_.clear(); 682 track_buffer_.clear();
671 config_change_pending_ = false; 683 config_change_pending_ = false;
672 last_output_buffer_timestamp_ = kNoTimestamp(); 684 last_output_buffer_timestamp_ = kNoTimestamp();
685 fade_out_preroll_index_ = 0;
686 fade_in_buffer_ = NULL;
673 } 687 }
674 688
675 bool SourceBufferStream::ShouldSeekToStartOfBuffered( 689 bool SourceBufferStream::ShouldSeekToStartOfBuffered(
676 base::TimeDelta seek_timestamp) const { 690 base::TimeDelta seek_timestamp) const {
677 if (ranges_.empty()) 691 if (ranges_.empty())
678 return false; 692 return false;
679 base::TimeDelta beginning_of_buffered = 693 base::TimeDelta beginning_of_buffered =
680 ranges_.front()->GetStartTimestamp(); 694 ranges_.front()->GetStartTimestamp();
681 return (seek_timestamp <= beginning_of_buffered && 695 return (seek_timestamp <= beginning_of_buffered &&
682 beginning_of_buffered < kSeekToStartFudgeRoom()); 696 beginning_of_buffered < kSeekToStartFudgeRoom());
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
1085 // If we're about to delete the selected range, also reset the seek state. 1099 // If we're about to delete the selected range, also reset the seek state.
1086 DCHECK((*itr)->GetStartTimestamp() >= duration); 1100 DCHECK((*itr)->GetStartTimestamp() >= duration);
1087 if (*itr == selected_range_) 1101 if (*itr == selected_range_)
1088 ResetSeekState(); 1102 ResetSeekState();
1089 DeleteAndRemoveRange(&itr); 1103 DeleteAndRemoveRange(&itr);
1090 } 1104 }
1091 } 1105 }
1092 1106
1093 SourceBufferStream::Status SourceBufferStream::GetNextBuffer( 1107 SourceBufferStream::Status SourceBufferStream::GetNextBuffer(
1094 scoped_refptr<StreamParserBuffer>* out_buffer) { 1108 scoped_refptr<StreamParserBuffer>* out_buffer) {
1109 if (!fade_in_buffer_) {
1110 const SourceBufferStream::Status status = GetNextBufferInternal(out_buffer);
1111
1112 // Just return if GetNextBufferInternal() failed or there's no fade out
1113 // preroll, there's nothing else to do.
1114 if (status != SourceBufferStream::kSuccess ||
1115 (*out_buffer)->GetFadeOutPreroll().empty()) {
1116 return status;
1117 }
1118
1119 // Setup fade in buffer and fall through into splice frame buffer handling.
1120 fade_out_preroll_index_ = 0;
1121 fade_in_buffer_ = *out_buffer;
1122 }
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 nit: I think you should set *out_buffer = NULL her
DaleCurtis 2014/01/15 22:40:56 Done.
1123
1124 DCHECK(fade_in_buffer_);
1125 const std::vector<scoped_refptr<StreamParserBuffer> >& fade_out_preroll =
1126 fade_in_buffer_->GetFadeOutPreroll();
1127
1128 // Are there any fade out buffers left to hand out?
1129 if (fade_out_preroll_index_ < fade_out_preroll.size()) {
1130 // Account for config changes which occur between fade out buffers.
1131 if (current_config_index_ !=
1132 fade_out_preroll[fade_out_preroll_index_]->GetConfigId()) {
1133 config_change_pending_ = true;
1134 DVLOG(1) << "Config change (fade out preroll config ID does not match).";
1135 return SourceBufferStream::kConfigChange;
1136 }
1137
1138 *out_buffer = fade_out_preroll[fade_out_preroll_index_++];
1139 return SourceBufferStream::kSuccess;
1140 }
1141
1142 // Did we hand out the last fade out buffer on the last call?
1143 if (fade_out_preroll_index_ == fade_out_preroll.size()) {
1144 fade_out_preroll_index_++;
1145 config_change_pending_ = true;
1146 DVLOG(1) << "Config change (forced for fade in of splice frame).";
1147 return SourceBufferStream::kConfigChange;
1148 }
1149
1150 // All fade out buffers have been handed out and a config change completed, so
1151 // hand out the final buffer for fade in. Because a config change is always
1152 // issued prior to handing out this buffer, any changes in config id have been
1153 // inherently handled.
1154 DCHECK_GT(fade_out_preroll_index_, fade_out_preroll.size());
1155 *out_buffer = fade_in_buffer_;
1156 fade_in_buffer_ = NULL;
1157 fade_out_preroll_index_ = 0;
1158 return SourceBufferStream::kSuccess;
1159 }
1160
1161 SourceBufferStream::Status SourceBufferStream::GetNextBufferInternal(
1162 scoped_refptr<StreamParserBuffer>* out_buffer) {
1095 CHECK(!config_change_pending_); 1163 CHECK(!config_change_pending_);
1096 1164
1097 if (!track_buffer_.empty()) { 1165 if (!track_buffer_.empty()) {
1098 DCHECK(!selected_range_); 1166 DCHECK(!selected_range_);
1099 if (track_buffer_.front()->GetConfigId() != current_config_index_) { 1167 scoped_refptr<StreamParserBuffer>& next_buffer = track_buffer_.front();
1168
1169 // If the next buffer is an audio splice frame, the next effective config id
1170 // comes from the first fade out preroll buffer.
1171 if (GetConfigId(next_buffer, 0) != current_config_index_) {
1100 config_change_pending_ = true; 1172 config_change_pending_ = true;
1101 DVLOG(1) << "Config change (track buffer config ID does not match)."; 1173 DVLOG(1) << "Config change (track buffer config ID does not match).";
1102 return kConfigChange; 1174 return kConfigChange;
1103 } 1175 }
1104 1176
1105 *out_buffer = track_buffer_.front(); 1177 *out_buffer = next_buffer;
1106 track_buffer_.pop_front(); 1178 track_buffer_.pop_front();
1107 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); 1179 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp();
1108 1180
1109 // If the track buffer becomes empty, then try to set the selected range 1181 // If the track buffer becomes empty, then try to set the selected range
1110 // based on the timestamp of this buffer being returned. 1182 // based on the timestamp of this buffer being returned.
1111 if (track_buffer_.empty()) 1183 if (track_buffer_.empty())
1112 SetSelectedRangeIfNeeded(last_output_buffer_timestamp_); 1184 SetSelectedRangeIfNeeded(last_output_buffer_timestamp_);
1113 1185
1114 return kSuccess; 1186 return kSuccess;
1115 } 1187 }
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
1331 append_config_index_ = video_configs_.size(); 1403 append_config_index_ = video_configs_.size();
1332 DVLOG(2) << "New video config - index: " << append_config_index_; 1404 DVLOG(2) << "New video config - index: " << append_config_index_;
1333 video_configs_.resize(video_configs_.size() + 1); 1405 video_configs_.resize(video_configs_.size() + 1);
1334 video_configs_[append_config_index_] = config; 1406 video_configs_[append_config_index_] = config;
1335 return true; 1407 return true;
1336 } 1408 }
1337 1409
1338 void SourceBufferStream::CompleteConfigChange() { 1410 void SourceBufferStream::CompleteConfigChange() {
1339 config_change_pending_ = false; 1411 config_change_pending_ = false;
1340 1412
1413 if (fade_in_buffer_) {
1414 current_config_index_ =
1415 GetConfigId(fade_in_buffer_, fade_out_preroll_index_);
1416 return;
1417 }
1418
1341 if (!track_buffer_.empty()) { 1419 if (!track_buffer_.empty()) {
1342 current_config_index_ = track_buffer_.front()->GetConfigId(); 1420 current_config_index_ = track_buffer_.front()->GetConfigId();
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 I think you need to use the helper function here t
DaleCurtis 2014/01/15 22:40:56 Done.
1343 return; 1421 return;
1344 } 1422 }
1345 1423
1346 if (selected_range_ && selected_range_->HasNextBuffer()) 1424 if (selected_range_ && selected_range_->HasNextBuffer())
1347 current_config_index_ = selected_range_->GetNextConfigId(); 1425 current_config_index_ = selected_range_->GetNextConfigId();
1348 } 1426 }
1349 1427
1350 void SourceBufferStream::SetSelectedRangeIfNeeded( 1428 void SourceBufferStream::SetSelectedRangeIfNeeded(
1351 const base::TimeDelta timestamp) { 1429 const base::TimeDelta timestamp) {
1352 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InSecondsF() << ")"; 1430 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InSecondsF() << ")";
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
1839 1917
1840 // Remove everything from |starting_point| onward. 1918 // Remove everything from |starting_point| onward.
1841 FreeBufferRange(starting_point, buffers_.end()); 1919 FreeBufferRange(starting_point, buffers_.end());
1842 } 1920 }
1843 1921
1844 bool SourceBufferRange::GetNextBuffer( 1922 bool SourceBufferRange::GetNextBuffer(
1845 scoped_refptr<StreamParserBuffer>* out_buffer) { 1923 scoped_refptr<StreamParserBuffer>* out_buffer) {
1846 if (!HasNextBuffer()) 1924 if (!HasNextBuffer())
1847 return false; 1925 return false;
1848 1926
1849 *out_buffer = buffers_.at(next_buffer_index_); 1927 *out_buffer = buffers_[next_buffer_index_];
1850 next_buffer_index_++; 1928 next_buffer_index_++;
1851 return true; 1929 return true;
1852 } 1930 }
1853 1931
1854 bool SourceBufferRange::HasNextBuffer() const { 1932 bool SourceBufferRange::HasNextBuffer() const {
1855 return next_buffer_index_ >= 0 && 1933 return next_buffer_index_ >= 0 &&
1856 next_buffer_index_ < static_cast<int>(buffers_.size()); 1934 next_buffer_index_ < static_cast<int>(buffers_.size());
1857 } 1935 }
1858 1936
1859 int SourceBufferRange::GetNextConfigId() const { 1937 int SourceBufferRange::GetNextConfigId() const {
1860 DCHECK(HasNextBuffer()); 1938 DCHECK(HasNextBuffer());
1861 return buffers_.at(next_buffer_index_)->GetConfigId(); 1939 const scoped_refptr<StreamParserBuffer>& next_buffer =
1940 buffers_[next_buffer_index_];
1941 // If the next buffer is an audio splice frame, the next effective config id
1942 // comes from the first fade out preroll buffer.
1943 return next_buffer->GetFadeOutPreroll().empty() ?
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 nit: Use the helper function here too.
DaleCurtis 2014/01/15 22:40:56 Done.
1944 next_buffer->GetConfigId() :
1945 next_buffer->GetFadeOutPreroll()[0]->GetConfigId();
1862 } 1946 }
1863 1947
1864 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { 1948 base::TimeDelta SourceBufferRange::GetNextTimestamp() const {
1865 DCHECK(!buffers_.empty()); 1949 DCHECK(!buffers_.empty());
1866 DCHECK(HasNextBufferPosition()); 1950 DCHECK(HasNextBufferPosition());
1867 1951
1868 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { 1952 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) {
1869 return kNoTimestamp(); 1953 return kNoTimestamp();
1870 } 1954 }
1871 1955
1872 return buffers_.at(next_buffer_index_)->GetDecodeTimestamp(); 1956 return buffers_[next_buffer_index_]->GetDecodeTimestamp();
1873 } 1957 }
1874 1958
1875 bool SourceBufferRange::HasNextBufferPosition() const { 1959 bool SourceBufferRange::HasNextBufferPosition() const {
1876 return next_buffer_index_ >= 0; 1960 return next_buffer_index_ >= 0;
1877 } 1961 }
1878 1962
1879 void SourceBufferRange::ResetNextBufferPosition() { 1963 void SourceBufferRange::ResetNextBufferPosition() {
1880 next_buffer_index_ = -1; 1964 next_buffer_index_ = -1;
1881 } 1965 }
1882 1966
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1984 return ComputeFudgeRoom(GetApproximateDuration()); 2068 return ComputeFudgeRoom(GetApproximateDuration());
1985 } 2069 }
1986 2070
1987 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { 2071 base::TimeDelta SourceBufferRange::GetApproximateDuration() const {
1988 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run(); 2072 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run();
1989 DCHECK(max_interbuffer_distance != kNoTimestamp()); 2073 DCHECK(max_interbuffer_distance != kNoTimestamp());
1990 return max_interbuffer_distance; 2074 return max_interbuffer_distance;
1991 } 2075 }
1992 2076
1993 } // namespace media 2077 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698