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

Unified Diff: media/filters/chunk_demuxer_unittest.cc

Issue 10545066: Implement support for 2 source ids (1 for audio and 1 for video). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 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
« media/filters/chunk_demuxer.cc ('K') | « media/filters/chunk_demuxer.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/chunk_demuxer_unittest.cc
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 6eed52c43c58107e4b293c5ccbce2595a1e785f5..629d2549e972e9c92f67f4820ce2296f4c9dd107 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -76,6 +76,12 @@ static void OnReadDone(const base::TimeDelta& expected_time,
*called = true;
}
+static void OnReadDone_EOSExpected(bool* called,
+ const scoped_refptr<DecoderBuffer>& buffer) {
+ EXPECT_TRUE(buffer->IsEndOfStream());
annacc 2012/06/07 22:42:07 I thought about modifying EndOfStreamHelper to che
+ *called = true;
+}
+
class MockChunkDemuxerClient : public ChunkDemuxerClient {
public:
MockChunkDemuxerClient() {}
@@ -175,19 +181,43 @@ class ChunkDemuxerTest : public testing::Test {
}
ChunkDemuxer::Status AddId() {
- std::vector<std::string> codecs(2);
- codecs[0] = "vp8";
- codecs[1] = "vorbis";
- return demuxer_->AddId(kSourceId, "video/webm", codecs);
+ return AddId(kSourceId, true, true);
+ }
+
+ ChunkDemuxer::Status AddId(const std::string& source_id,
+ bool has_audio, bool has_video) {
+ std::vector<std::string> codecs;
+ std::string type;
+
+ if (has_audio) {
+ codecs.push_back("vorbis");
+ type = "audio/webm";
+ }
+
+ if (has_video) {
+ codecs.push_back("vp8");
+ type = "video/webm";
+ }
+
+ if (!has_audio && !has_video) {
+ return AddId(kSourceId, true, true);
+ }
annacc 2012/06/07 22:42:07 This is required because TestInit appends info tra
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 This looks right to me.
+
+ return demuxer_->AddId(source_id, type, codecs);
}
bool AppendData(const uint8* data, size_t length) {
+ return AppendData(kSourceId, data, length);
+ }
+
+ bool AppendData(const std::string& source_id,
+ const uint8* data, size_t length) {
CHECK(length);
EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber())
.WillRepeatedly(SaveArg<1>(&buffered_bytes_));
EXPECT_CALL(host_, SetNetworkActivity(true))
.Times(AnyNumber());
- return demuxer_->AppendData(kSourceId, data, length);
+ return demuxer_->AppendData(source_id, data, length);
}
bool AppendDataInPieces(const uint8* data, size_t length) {
@@ -212,11 +242,18 @@ class ChunkDemuxerTest : public testing::Test {
bool AppendInfoTracks(bool has_audio, bool has_video,
bool video_content_encoded) {
+ return AppendInfoTracks(kSourceId, has_audio, has_video,
+ video_content_encoded);
+ }
+
+ bool AppendInfoTracks(const std::string& source_id,
+ bool has_audio, bool has_video,
+ bool video_content_encoded) {
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
CreateInfoTracks(has_audio, has_video, video_content_encoded,
&info_tracks, &info_tracks_size);
- return AppendData(info_tracks.get(), info_tracks_size);
+ return AppendData(source_id, info_tracks.get(), info_tracks_size);
}
void InitDoneCalled(PipelineStatus expected_status,
@@ -243,12 +280,29 @@ class ChunkDemuxerTest : public testing::Test {
demuxer_->Initialize(
&host_, CreateInitDoneCB(kDefaultDuration(), expected_status));
- if (AddId() != ChunkDemuxer::kOk)
+ if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk)
return false;
return AppendInfoTracks(has_audio, has_video, video_content_encoded);
}
+ bool InitDemuxerAudioAndVideoSources(const std::string& audio_id,
+ const std::string& video_id) {
+ EXPECT_CALL(*client_, DemuxerOpened(_));
+ demuxer_->Initialize(
+ &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK));
+
+ if (AddId(audio_id, true, false) != ChunkDemuxer::kOk)
+ return false;
+ if (AddId(video_id, false, true) != ChunkDemuxer::kOk)
+ return false;
+
+ bool success;
+ success = AppendInfoTracks(audio_id, true, false, false);
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 Move this assignement to the line above.
annacc 2012/06/08 22:12:23 Done.
+ success = success && AppendInfoTracks(video_id, false, true, false);
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 You could use &= here
annacc 2012/06/08 22:12:23 Done.
+ return success;
+ }
+
void ShutdownDemuxer() {
if (demuxer_) {
EXPECT_CALL(*client_, DemuxerClosed());
@@ -315,6 +369,32 @@ class ChunkDemuxerTest : public testing::Test {
return cb.Finish();
}
+ scoped_ptr<Cluster> GenerateSingleStreamCluster(int audio_timecode,
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 how about just timecode since I don't see anything
annacc 2012/06/08 22:12:23 Whoops, leftover from a previous idea. Done.
+ int block_count,
+ int track_number,
+ int block_duration) {
+ CHECK_GT(block_count, 0);
+
+ int size = 10;
+ scoped_array<uint8> data(new uint8[size]);
+
+ ClusterBuilder cb;
+ cb.SetClusterTimecode(audio_timecode);
+
+ // Create simple blocks for everything except the last block.
+ for (int i = 0; i < block_count - 1; i++) {
+ cb.AddSimpleBlock(track_number, audio_timecode, kWebMFlagKeyframe,
+ data.get(), size);
+ audio_timecode += block_duration;
+ }
+
+ // Make the last block a BlockGroups so that it doesn't get delayed by the
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 s/BlockGroups/BlockGroup
annacc 2012/06/08 22:12:23 Done.
+ // block duration calculation logic.
+ cb.AddBlockGroup(track_number, audio_timecode, block_duration,
+ kWebMFlagKeyframe, data.get(), size);
+ return cb.Finish();
+ }
+
void GenerateExpectedReads(int timecode, int block_count,
DemuxerStream* audio,
DemuxerStream* video) {
@@ -364,11 +444,18 @@ class ChunkDemuxerTest : public testing::Test {
bool ParseWebMFile(const std::string& filename,
const BufferTimestamps* timestamps,
const base::TimeDelta& duration) {
+ return ParseWebMFile(filename, timestamps, duration, true, true);
+ }
+
+ bool ParseWebMFile(const std::string& filename,
+ const BufferTimestamps* timestamps,
+ const base::TimeDelta& duration,
+ bool has_audio, bool has_video) {
EXPECT_CALL(*client_, DemuxerOpened(_));
demuxer_->Initialize(
&host_, CreateInitDoneCB(duration, PIPELINE_OK));
- if (AddId() != ChunkDemuxer::kOk)
+ if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk)
return false;
// Read a WebM file into memory and send the data to the demuxer.
@@ -956,7 +1043,8 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_AudioOnly) {
};
ASSERT_TRUE(ParseWebMFile("bear-320x240-audio-only.webm", buffer_timestamps,
- base::TimeDelta::FromMilliseconds(2744)));
+ base::TimeDelta::FromMilliseconds(2744),
+ true, false));
}
TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) {
@@ -970,7 +1058,8 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) {
};
ASSERT_TRUE(ParseWebMFile("bear-320x240-video-only.webm", buffer_timestamps,
- base::TimeDelta::FromMilliseconds(2703)));
+ base::TimeDelta::FromMilliseconds(2703),
+ false, true));
}
TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) {
@@ -1096,4 +1185,162 @@ TEST_F(ChunkDemuxerTest, TestAVHeadersWithVideoOnlyType) {
ASSERT_TRUE(AppendInfoTracks(true, true, false));
}
+TEST_F(ChunkDemuxerTest, TestAddSeparateSourcesForAudioAndVideo) {
+ std::string audio_id = "audio1";
+ std::string video_id = "video1";
+ ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
+
+ scoped_refptr<DemuxerStream> audio =
+ demuxer_->GetStream(DemuxerStream::AUDIO);
+ scoped_refptr<DemuxerStream> video =
+ demuxer_->GetStream(DemuxerStream::VIDEO);
+
+ bool audio_read_done = false;
+ bool video_read_done = false;
+ audio->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(0),
+ &audio_read_done));
+
+ video->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(0),
+ &video_read_done));
+
+ scoped_ptr<Cluster> cluster_a(
+ GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration));
+
+ scoped_ptr<Cluster> cluster_v(
+ GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration));
+
+ // Append audio and video data into separate source ids.
+ ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size()));
+ ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size()));
+
+ EXPECT_TRUE(audio_read_done);
+ EXPECT_TRUE(video_read_done);
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 Consider creating the single stream equivalent of
annacc 2012/06/08 22:12:23 Done.
+}
+
+TEST_F(ChunkDemuxerTest, TestAddIdFailures) {
+ EXPECT_CALL(*client_, DemuxerOpened(_));
+ demuxer_->Initialize(
+ &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK));
+
+ std::string audio_id = "audio1";
+ std::string video_id = "video1";
+
+ ASSERT_EQ(AddId(audio_id, true, false), ChunkDemuxer::kOk);
+
+ // Adding an id with audio/video should fail because we already added audio.
+ ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit);
+
+ ASSERT_TRUE(AppendInfoTracks(audio_id, true, false, false));
+
+ // Adding an id after append should fail.
+ ASSERT_EQ(AddId(video_id, false, true), ChunkDemuxer::kReachedIdLimit);
+}
+
+// Test that Read() calls after a RemoveId() return "end of stream" buffers.
+TEST_F(ChunkDemuxerTest, TestRemoveId) {
+ std::string audio_id = "audio1";
+ std::string video_id = "video1";
+ ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
+
+ scoped_ptr<Cluster> cluster_a(
+ GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration));
+
+ scoped_ptr<Cluster> cluster_v(
+ GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration));
+
+ // Append audio and video data into separate source ids.
+ ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size()));
+ ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size()));
+
+ // Read() from audio should return normal buffers.
+ bool audio_read_done = false;
+ scoped_refptr<DemuxerStream> audio =
+ demuxer_->GetStream(DemuxerStream::AUDIO);
+ audio->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(0),
+ &audio_read_done));
+ EXPECT_TRUE(audio_read_done);
+
+ // Remove the audio id.
+ demuxer_->RemoveId(audio_id);
+
+ // Read() from audio should return "end of stream" buffers.
+ audio_read_done = false;
+ audio->Read(base::Bind(&OnReadDone_EOSExpected,
+ &audio_read_done));
+ EXPECT_TRUE(audio_read_done);
+
+ // Read() from video should still return normal buffers.
+ bool video_read_done = false;
+ scoped_refptr<DemuxerStream> video =
+ demuxer_->GetStream(DemuxerStream::VIDEO);
+ video->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(0),
+ &video_read_done));
+ EXPECT_TRUE(video_read_done);
+}
+
+// Test that Seek() successfully seeks to all source IDs.
+TEST_F(ChunkDemuxerTest, TestSeekAudioAndVideoSources) {
+ std::string audio_id = "audio1";
+ std::string video_id = "video1";
+ ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
+
+ scoped_ptr<Cluster> cluster_a1(
+ GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration));
+
+ scoped_ptr<Cluster> cluster_v1(
+ GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration));
+
+ ASSERT_TRUE(AppendData(audio_id, cluster_a1->data(), cluster_a1->size()));
+ ASSERT_TRUE(AppendData(video_id, cluster_v1->data(), cluster_v1->size()));
+
+ // Read() should return buffers at 0.
+ bool audio_read_done = false;
+ bool video_read_done = false;
+ scoped_refptr<DemuxerStream> audio =
+ demuxer_->GetStream(DemuxerStream::AUDIO);
+ scoped_refptr<DemuxerStream> video =
+ demuxer_->GetStream(DemuxerStream::VIDEO);
+
+ audio->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(0),
+ &audio_read_done));
+ video->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(0),
+ &video_read_done));
+ EXPECT_TRUE(audio_read_done);
+ EXPECT_TRUE(video_read_done);
+
+ // Seek to 3.
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 Might want to also indicate that 3 is used because
annacc 2012/06/08 22:12:23 Done.
+ demuxer_->StartWaitingForSeek();
+ demuxer_->Seek(base::TimeDelta::FromSeconds(3),
+ NewExpectedStatusCB(PIPELINE_OK));
+
+ scoped_ptr<Cluster> cluster_a2(
+ GenerateSingleStreamCluster(3000, 4, kAudioTrackNum,
+ kAudioBlockDuration));
+
+ scoped_ptr<Cluster> cluster_v2(
+ GenerateSingleStreamCluster(3000, 4, kVideoTrackNum,
+ kVideoBlockDuration));
+
+ ASSERT_TRUE(AppendData(audio_id, cluster_a2->data(), cluster_a2->size()));
+ ASSERT_TRUE(AppendData(video_id, cluster_v2->data(), cluster_v2->size()));
+
+ // Read() should return buffers at 3 after the seek.
+ audio_read_done = false;
+ video_read_done = false;
+ audio->Read(base::Bind(&OnReadDone,
acolwell GONE FROM CHROMIUM 2012/06/08 00:29:07 WDYT about putting these reads right above the clu
+ base::TimeDelta::FromSeconds(3),
+ &audio_read_done));
+ video->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromSeconds(3),
+ &video_read_done));
+ EXPECT_TRUE(audio_read_done);
+ EXPECT_TRUE(video_read_done);
+}
+
} // namespace media
« media/filters/chunk_demuxer.cc ('K') | « media/filters/chunk_demuxer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698