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

Unified Diff: media/filters/source_buffer_stream_unittest.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 side-by-side diff with in-line comments
Download patch
Index: media/filters/source_buffer_stream_unittest.cc
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
index 9e7373a16ad37d6bf172642fe2388185599b935a..04da573c9c6381cdc1a3f1fc4c877e4c1cc565eb 100644
--- a/media/filters/source_buffer_stream_unittest.cc
+++ b/media/filters/source_buffer_stream_unittest.cc
@@ -6,6 +6,8 @@
#include <string>
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -27,8 +29,8 @@ class SourceBufferStreamTest : public testing::Test {
protected:
SourceBufferStreamTest() {
config_ = TestVideoConfig::Normal();
- stream_.reset(new SourceBufferStream(config_, LogCB()));
SetStreamInfo(kDefaultFramesPerSecond, kDefaultKeyframesPerSecond);
+ stream_.reset(new SourceBufferStream(config_, log_cb()));
}
void SetMemoryLimit(int buffers_of_data) {
@@ -248,6 +250,11 @@ class SourceBufferStreamTest : public testing::Test {
<< "\nActual: " << actual.AsHumanReadableString();
}
+ const LogCB log_cb() {
+ return base::Bind(&SourceBufferStreamTest::DebugMediaLog,
+ base::Unretained(this));
+ }
+
base::TimeDelta frame_duration() const { return frame_duration_; }
scoped_ptr<SourceBufferStream> stream_;
@@ -304,6 +311,21 @@ class SourceBufferStreamTest : public testing::Test {
EXPECT_EQ(expect_success, stream_->Append(queue));
}
+ // AppendBuffers() allows for the generation of StreamParserBuffers from coded
+ // strings of timestamps separated by spaces. Supported syntax:
+ //
+ // ##:
+ // Generates a StreamParserBuffer with decode timestamp ##. E.g., "0 1 2 3".
+ //
+ // ##K:
+ // Indicates the buffer with timestamp ## reflects a keyframe. E.g., "0K 1".
+ //
+ // S(a# ... y# z#)
+ // Indicates a splice frame buffer should be created with timestamp z#. The
+ // preceding timestamps a# ... y# will be treated as the fade out preroll for
+ // the splice frame. If a timestamp within the preroll ends with C the config
+ // id to use for that and subsequent preroll appends is incremented by one.
+ // The config id for non-splice frame appends will not be affected.
void AppendBuffers(const std::string& buffers_to_append,
bool start_new_segment, bool one_by_one,
bool expect_success) {
@@ -312,14 +334,39 @@ class SourceBufferStreamTest : public testing::Test {
CHECK_GT(timestamps.size(), 0u);
+ bool splice_frame = false;
+ size_t splice_config_id = stream_->append_config_index_;
+ std::vector<scoped_refptr<StreamParserBuffer> > fade_out_preroll;
SourceBufferStream::BufferQueue buffers;
for (size_t i = 0; i < timestamps.size(); i++) {
bool is_keyframe = false;
+ bool last_splice_frame = false;
+ // Handle splice frame starts.
+ if (StartsWithASCII(timestamps[i], "S(", true)) {
+ splice_frame = true;
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 nit: Add DCHECK(!splice_frame) to avoid allowing S
DaleCurtis 2014/01/15 22:40:56 Done.
+ // Remove the "S(" off of the token.
+ timestamps[i] = timestamps[i].substr(2, timestamps[i].length());
+ }
+ if (splice_frame && EndsWith(timestamps[i], ")", true)) {
+ splice_frame = false;
+ last_splice_frame = true;
+ // Remove the ")" off of the token.
+ timestamps[i] = timestamps[i].substr(0, timestamps[i].length() - 1);
+ }
+ // Handle config changes within the splice frame.
+ if (splice_frame && EndsWith(timestamps[i], "C", true)) {
+ splice_config_id++;
+ CHECK(splice_config_id < stream_->audio_configs_.size() ||
+ splice_config_id < stream_->video_configs_.size());
+ // Remove the "C" off of the token.
+ timestamps[i] = timestamps[i].substr(0, timestamps[i].length() - 1);
+ }
if (EndsWith(timestamps[i], "K", true)) {
is_keyframe = true;
// Remove the "K" off of the token.
timestamps[i] = timestamps[i].substr(0, timestamps[i].length() - 1);
}
+
int time_in_ms;
CHECK(base::StringToInt(timestamps[i], &time_in_ms));
@@ -330,6 +377,25 @@ class SourceBufferStreamTest : public testing::Test {
base::TimeDelta::FromMilliseconds(time_in_ms);
buffer->SetDecodeTimestamp(timestamp);
+ if (splice_frame) {
+ if (!fade_out_preroll.empty()) {
+ // Enforce strictly monotonically increasing timestamps.
+ CHECK_GT(
+ timestamp.InMicroseconds(),
+ fade_out_preroll.back()->GetDecodeTimestamp().InMicroseconds());
+ }
+ buffer->SetConfigId(splice_config_id);
+ fade_out_preroll.push_back(buffer);
+ continue;
+ }
+
+ if (last_splice_frame) {
+ // Forbid splice frames without preroll.
+ CHECK(!fade_out_preroll.empty());
+ buffer->SetFadeOutPreroll(fade_out_preroll);
+ fade_out_preroll.clear();
+ }
+
if (i == 0u && start_new_segment)
stream_->OnNewMediaSegment(timestamp);
@@ -349,6 +415,10 @@ class SourceBufferStreamTest : public testing::Test {
}
}
+ void DebugMediaLog(const std::string& log) {
+ DVLOG(1) << log;
+ }
+
int frames_per_second_;
int keyframes_per_second_;
base::TimeDelta frame_duration_;
@@ -1346,7 +1416,7 @@ TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer) {
CheckExpectedRangesByTimestamp("{ [10,160) }");
// Seek to 70ms.
- SeekToTimestamp(base::TimeDelta::FromMilliseconds(10));
+ SeekToTimestamp(base::TimeDelta::FromMilliseconds(70));
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 I'm assuming this is just to make the comment and
DaleCurtis 2014/01/15 22:40:56 Correct, test passes as before.
CheckExpectedBuffers("10K 40");
// Overlap with a new segment from 0 to 120ms.
@@ -1504,7 +1574,7 @@ TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer6) {
CheckExpectedRangesByTimestamp("{ [10,160) [200,260) }");
// Seek to 70ms.
- SeekToTimestamp(base::TimeDelta::FromMilliseconds(10));
+ SeekToTimestamp(base::TimeDelta::FromMilliseconds(70));
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 ditto?
DaleCurtis 2014/01/15 22:40:56 Ditto.
CheckExpectedBuffers("10K 40");
// Overlap with a new segment from 0 to 120ms.
@@ -3000,7 +3070,7 @@ TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Overlap_3) {
TEST_F(SourceBufferStreamTest, SameTimestamp_Audio) {
AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
44100, NULL, 0, false);
- stream_.reset(new SourceBufferStream(config, LogCB()));
+ stream_.reset(new SourceBufferStream(config, log_cb()));
Seek(0);
NewSegmentAppend("0K 0K 30K 30 60 60");
CheckExpectedBuffers("0K 0K 30K 30 60 60");
@@ -3009,7 +3079,7 @@ TEST_F(SourceBufferStreamTest, SameTimestamp_Audio) {
TEST_F(SourceBufferStreamTest, SameTimestamp_Audio_Invalid_1) {
AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
44100, NULL, 0, false);
- stream_.reset(new SourceBufferStream(config, LogCB()));
+ stream_.reset(new SourceBufferStream(config, log_cb()));
Seek(0);
NewSegmentAppend_ExpectFailure("0K 30 30K 60");
}
@@ -3250,7 +3320,6 @@ TEST_F(SourceBufferStreamTest, Remove_GOPBeingAppended) {
CheckExpectedBuffers("240K 270 300");
}
-
TEST_F(SourceBufferStreamTest,
Remove_PreviousAppendDestroyedAndOverwriteExistingRange) {
SeekToTimestamp(base::TimeDelta::FromMilliseconds(90));
@@ -3275,6 +3344,120 @@ TEST_F(SourceBufferStreamTest,
CheckExpectedBuffers("90K 121 151");
}
+TEST_F(SourceBufferStreamTest, SpliceFrame_Basic) {
+ Seek(0);
+ NewSegmentAppend("0K S(3K 6 9 10) 15 20 S(25K 30 35) 40");
+ CheckExpectedBuffers("0K 3K 6 9");
acolwell GONE FROM CHROMIUM 2014/01/15 19:28:50 Consider adding support for "C" to CheckExpectedBu
DaleCurtis 2014/01/15 22:40:56 Great idea. It loses the ability to verify the con
+
+ scoped_refptr<StreamParserBuffer> buffer;
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ stream_->GetCurrentVideoDecoderConfig();
+
+ CheckExpectedBuffers("10 15 20 25K 30");
+
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ stream_->GetCurrentVideoDecoderConfig();
+
+ CheckExpectedBuffers("35 40");
+ CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest, SpliceFrame_SeekClearsSplice) {
+ Seek(0);
+ NewSegmentAppend("0K S(3K 6 9 10) 15K 20");
+ CheckExpectedBuffers("0K 3K 6");
+
+ SeekToTimestamp(base::TimeDelta::FromMilliseconds(15));
+ CheckExpectedBuffers("15K 20");
+ CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest, SpliceFrame_SeekClearsSpliceFromTrackBuffer) {
+ Seek(0);
+ NewSegmentAppend("0K 2K S(3K 6 9 10) 15K 20");
+ CheckExpectedBuffers("0K 2K");
+
+ // Overlap the existing segment.
+ NewSegmentAppend("5K 15K 20");
+ CheckExpectedBuffers("3K 6");
+
+ SeekToTimestamp(base::TimeDelta::FromMilliseconds(15));
+ CheckExpectedBuffers("15K 20");
+ CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest, SpliceFrame_ConfigChangeWithinSplice) {
+ VideoDecoderConfig new_config = TestVideoConfig::Large();
+ ASSERT_FALSE(new_config.Matches(config_));
+ CheckConfig(config_);
+
+ // Add a new video config, then reset the config index back to the original.
+ stream_->UpdateVideoConfig(new_config);
+ stream_->UpdateVideoConfig(config_);
+
+ Seek(0);
+ CheckConfig(config_);
+ NewSegmentAppend("0K S(3K 6C 9 10) 15");
+ CheckExpectedBuffers("0K 3K");
+
+ scoped_refptr<StreamParserBuffer> buffer;
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ CheckConfig(new_config);
+ CheckExpectedBuffers("6 9");
+
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ CheckConfig(config_);
+ CheckExpectedBuffers("10 15");
+ CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest, SpliceFrame_BasicFromTrackBuffer) {
+ Seek(0);
+ NewSegmentAppend("0K 5K S(8K 9 10) 20");
+ CheckExpectedBuffers("0K 5K");
+
+ // Overlap the existing segment.
+ NewSegmentAppend("5K 20");
+ CheckExpectedBuffers("8K 9");
+
+ scoped_refptr<StreamParserBuffer> buffer;
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ stream_->GetCurrentVideoDecoderConfig();
+
+ CheckExpectedBuffers("10 20");
+ CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest,
+ SpliceFrame_ConfigChangeWithinSpliceFromTrackBuffer) {
+ VideoDecoderConfig new_config = TestVideoConfig::Large();
+ ASSERT_FALSE(new_config.Matches(config_));
+ CheckConfig(config_);
+
+ // Add a new video config, then reset the config index back to the original.
+ stream_->UpdateVideoConfig(new_config);
+ stream_->UpdateVideoConfig(config_);
+
+ Seek(0);
+ CheckConfig(config_);
+ NewSegmentAppend("0K 5K S(7K 8C 9 10) 20");
+ CheckExpectedBuffers("0K 5K");
+
+ // Overlap the existing segment.
+ NewSegmentAppend("5K 20");
+ CheckExpectedBuffers("7K");
+
+ scoped_refptr<StreamParserBuffer> buffer;
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ CheckConfig(new_config);
+ CheckExpectedBuffers("8 9");
+
+ EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange);
+ CheckConfig(config_);
+ CheckExpectedBuffers("10 20");
+ CheckNoNextBuffer();
+}
+
// TODO(vrk): Add unit tests where keyframes are unaligned between streams.
// (crbug.com/133557)
« media/filters/source_buffer_stream.cc ('K') | « media/filters/source_buffer_stream.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698