summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-18 05:19:40 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-18 05:19:40 +0000
commit0e1d89e963f250df7c7c18b651986f7715a8e509 (patch)
tree284adc4d75827f2e449d7cde116e5970ebe0955d /media
parent925dec1cf8e2574f24d09cb39fe2f1ad8346d28b (diff)
downloadchromium_src-0e1d89e963f250df7c7c18b651986f7715a8e509.zip
chromium_src-0e1d89e963f250df7c7c18b651986f7715a8e509.tar.gz
chromium_src-0e1d89e963f250df7c7c18b651986f7715a8e509.tar.bz2
Update WebMClusterParser to compute durations for all StreamParserBuffers.
BUG=127916 TEST=WebMClusterParserTest.* Review URL: https://chromiumcodereview.appspot.com/10382200 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137826 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/stream_parser_buffer.cc1
-rw-r--r--media/filters/chunk_demuxer_unittest.cc252
-rw-r--r--media/filters/pipeline_integration_test.cc2
-rw-r--r--media/webm/webm_cluster_parser.cc97
-rw-r--r--media/webm/webm_cluster_parser.h37
-rw-r--r--media/webm/webm_cluster_parser_unittest.cc8
-rw-r--r--media/webm/webm_tracks_parser.cc11
7 files changed, 218 insertions, 190 deletions
diff --git a/media/base/stream_parser_buffer.cc b/media/base/stream_parser_buffer.cc
index 3c765b1..ed4150c 100644
--- a/media/base/stream_parser_buffer.cc
+++ b/media/base/stream_parser_buffer.cc
@@ -12,6 +12,7 @@ StreamParserBuffer::StreamParserBuffer(const uint8* data, int data_size,
bool is_keyframe)
: DataBuffer(data, data_size),
is_keyframe_(is_keyframe) {
+ SetDuration(kNoTimestamp());
}
scoped_refptr<StreamParserBuffer> StreamParserBuffer::CreateEOSBuffer() {
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 43ec4ad..45c3a7d 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -39,6 +39,9 @@ static const int kVideoTrackEntryHeaderSize = kVideoTrackSizeOffset +
static const int kVideoTrackNum = 1;
static const int kAudioTrackNum = 2;
+static const int kAudioBlockDuration = 23;
+static const int kVideoBlockDuration = 33;
+
static const char* kSourceId = "SourceId";
base::TimeDelta kDefaultDuration() {
@@ -59,7 +62,7 @@ static void WriteInt64(uint8* buffer, int64 number) {
}
MATCHER_P(HasTimestamp, timestamp_in_ms, "") {
- return !arg->IsEndOfStream() &&
+ return arg && !arg->IsEndOfStream() &&
arg->GetTimestamp().InMilliseconds() == timestamp_in_ms;
}
@@ -177,6 +180,7 @@ class ChunkDemuxerTest : public testing::Test {
}
bool AppendData(const uint8* data, size_t length) {
+ CHECK(length);
EXPECT_CALL(host_, SetBufferedBytes(_)).Times(AnyNumber());
EXPECT_CALL(host_, SetNetworkActivity(true))
.Times(AnyNumber());
@@ -253,10 +257,74 @@ class ChunkDemuxerTest : public testing::Test {
cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data));
}
- void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode,
- int size) {
+ scoped_ptr<Cluster> GenerateCluster(int timecode, int block_count) {
+ CHECK_GT(block_count, 0);
+
+ int size = 10;
scoped_array<uint8> data(new uint8[size]);
- cb->AddSimpleBlock(track_num, timecode, 0, data.get(), size);
+
+ ClusterBuilder cb;
+ cb.SetClusterTimecode(timecode);
+ int audio_timecode = timecode;
+ int video_timecode = timecode + 1;
+
+ if (block_count == 1) {
+ cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, 0,
+ data.get(), size);
+ return cb.Finish();
+ }
+
+ // Create simple blocks for everything except the last 2 blocks.
+ for (int i = 0; i < block_count - 2; i++) {
+ if (audio_timecode <= video_timecode) {
+ cb.AddSimpleBlock(kAudioTrackNum, audio_timecode, 0, data.get(), size);
+ audio_timecode += kAudioBlockDuration;
+ continue;
+ }
+
+ cb.AddSimpleBlock(kVideoTrackNum, video_timecode, 0, data.get(), size);
+ video_timecode += kVideoBlockDuration;
+ }
+
+ // Make the last 2 blocks BlockGroups so that they don't get delayed by the
+ // block duration calculation logic.
+ if (audio_timecode <= video_timecode) {
+ cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, 0,
+ data.get(), size);
+ cb.AddBlockGroup(kVideoTrackNum, video_timecode, kVideoBlockDuration, 0,
+ data.get(), size);
+ } else {
+ cb.AddBlockGroup(kVideoTrackNum, video_timecode, kVideoBlockDuration, 0,
+ data.get(), size);
+ cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, 0,
+ data.get(), size);
+ }
+
+ return cb.Finish();
+ }
+
+ void GenerateExpectedReads(int timecode, int block_count,
+ DemuxerStream* audio,
+ DemuxerStream* video) {
+ CHECK_GT(block_count, 0);
+ int audio_timecode = timecode;
+ int video_timecode = timecode + 1;
+
+ if (block_count == 1) {
+ ExpectRead(audio, audio_timecode);
+ return;
+ }
+
+ for (int i = 0; i < block_count; i++) {
+ if (audio_timecode <= video_timecode) {
+ ExpectRead(audio, audio_timecode);
+ audio_timecode += kAudioBlockDuration;
+ continue;
+ }
+
+ ExpectRead(video, video_timecode);
+ video_timecode += kVideoBlockDuration;
+ }
}
MOCK_METHOD1(ReadDone, void(const scoped_refptr<Buffer>&));
@@ -416,10 +484,7 @@ TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) {
EXPECT_CALL(*this, Checkpoint(2));
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kVideoTrackNum, 0);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 4));
Checkpoint(1);
@@ -442,28 +507,20 @@ TEST_F(ChunkDemuxerTest, TestSeekWhileParsingCluster) {
InSequence s;
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 1);
- AddSimpleBlock(&cb, kVideoTrackNum, 2);
- AddSimpleBlock(&cb, kAudioTrackNum, 10);
- AddSimpleBlock(&cb, kVideoTrackNum, 20);
- scoped_ptr<Cluster> cluster_a(cb.Finish());
-
- cb.SetClusterTimecode(5000);
- AddSimpleBlock(&cb, kAudioTrackNum, 5000);
- AddSimpleBlock(&cb, kVideoTrackNum, 5005);
- AddSimpleBlock(&cb, kAudioTrackNum, 5007);
- AddSimpleBlock(&cb, kVideoTrackNum, 5035);
- scoped_ptr<Cluster> cluster_b(cb.Finish());
+ scoped_ptr<Cluster> cluster_a(GenerateCluster(0, 6));
+ scoped_ptr<Cluster> cluster_b(GenerateCluster(5000, 6));
// Append all but the last byte so that everything but
// the last block can be parsed.
ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size() - 1));
- ExpectRead(audio, 1);
- ExpectRead(video, 2);
- ExpectRead(audio, 10);
+ ExpectRead(audio, 0);
+ ExpectRead(video, 1);
+ ExpectRead(audio, kAudioBlockDuration);
+ // Note: We skip trying to read a video buffer here because computing
+ // the duration for this block relies on successfully parsing the last block
+ // in the cluster the cluster.
+ ExpectRead(audio, 2 * kAudioBlockDuration);
demuxer_->FlushData();
demuxer_->Seek(base::TimeDelta::FromSeconds(5),
@@ -473,10 +530,7 @@ TEST_F(ChunkDemuxerTest, TestSeekWhileParsingCluster) {
// Append the new cluster and verify that only the blocks
// in the new cluster are returned.
ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size()));
- ExpectRead(audio, 5000);
- ExpectRead(video, 5005);
- ExpectRead(audio, 5007);
- ExpectRead(video, 5035);
+ GenerateExpectedReads(5000, 6, audio, video);
}
// Test the case where AppendData() is called before Init().
@@ -501,18 +555,14 @@ TEST_F(ChunkDemuxerTest, TestRead) {
bool audio_read_done = false;
bool video_read_done = false;
audio->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(32),
+ base::TimeDelta::FromMilliseconds(0),
&audio_read_done));
video->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(123),
+ base::TimeDelta::FromMilliseconds(1),
&video_read_done));
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 32);
- AddSimpleBlock(&cb, kVideoTrackNum, 123);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 4));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -523,25 +573,13 @@ TEST_F(ChunkDemuxerTest, TestRead) {
TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) {
ASSERT_TRUE(InitDemuxer(true, true, false));
- ClusterBuilder cb;
-
- cb.SetClusterTimecode(10);
- AddSimpleBlock(&cb, kAudioTrackNum, 10);
- AddSimpleBlock(&cb, kVideoTrackNum, 10);
- AddSimpleBlock(&cb, kAudioTrackNum, 33);
- AddSimpleBlock(&cb, kVideoTrackNum, 43);
- scoped_ptr<Cluster> cluster_a(cb.Finish());
+ scoped_ptr<Cluster> cluster_a(GenerateCluster(10, 4));
ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size()));
// Cluster B starts before cluster_a and has data
// that overlaps.
- cb.SetClusterTimecode(5);
- AddSimpleBlock(&cb, kAudioTrackNum, 5);
- AddSimpleBlock(&cb, kVideoTrackNum, 7);
- AddSimpleBlock(&cb, kAudioTrackNum, 28);
- AddSimpleBlock(&cb, kVideoTrackNum, 40);
- scoped_ptr<Cluster> cluster_b(cb.Finish());
+ scoped_ptr<Cluster> cluster_b(GenerateCluster(5, 4));
// Make sure that AppendData() fails because this cluster data
// is before previous data.
@@ -549,10 +587,7 @@ TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) {
ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size()));
// Verify that AppendData() doesn't accept more data now.
- cb.SetClusterTimecode(45);
- AddSimpleBlock(&cb, kAudioTrackNum, 45);
- AddSimpleBlock(&cb, kVideoTrackNum, 45);
- scoped_ptr<Cluster> cluster_c(cb.Finish());
+ scoped_ptr<Cluster> cluster_c(GenerateCluster(45, 2));
EXPECT_FALSE(demuxer_->AppendData(kSourceId, cluster_c->data(),
cluster_c->size()));
}
@@ -575,10 +610,7 @@ TEST_F(ChunkDemuxerTest, TestNonMonotonicButAboveClusterTimecode) {
ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size()));
// Verify that AppendData() doesn't accept more data now.
- cb.SetClusterTimecode(20);
- AddSimpleBlock(&cb, kAudioTrackNum, 20);
- AddSimpleBlock(&cb, kVideoTrackNum, 20);
- scoped_ptr<Cluster> cluster_b(cb.Finish());
+ scoped_ptr<Cluster> cluster_b(GenerateCluster(20, 2));
EXPECT_FALSE(demuxer_->AppendData(kSourceId, cluster_b->data(),
cluster_b->size()));
}
@@ -601,10 +633,7 @@ TEST_F(ChunkDemuxerTest, TestBackwardsAndBeforeClusterTimecode) {
ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size()));
// Verify that AppendData() doesn't accept more data now.
- cb.SetClusterTimecode(6);
- AddSimpleBlock(&cb, kAudioTrackNum, 6);
- AddSimpleBlock(&cb, kVideoTrackNum, 6);
- scoped_ptr<Cluster> cluster_b(cb.Finish());
+ scoped_ptr<Cluster> cluster_b(GenerateCluster(6, 2));
EXPECT_FALSE(demuxer_->AppendData(kSourceId, cluster_b->data(),
cluster_b->size()));
}
@@ -651,10 +680,7 @@ TEST_F(ChunkDemuxerTest, TestMonotonicallyIncreasingTimestampsAcrossClusters) {
ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size()));
// Verify that AppendData() doesn't accept more data now.
- cb.SetClusterTimecode(10);
- AddSimpleBlock(&cb, kAudioTrackNum, 10);
- AddSimpleBlock(&cb, kVideoTrackNum, 10);
- scoped_ptr<Cluster> cluster_c(cb.Finish());
+ scoped_ptr<Cluster> cluster_c(GenerateCluster(10, 2));
EXPECT_FALSE(demuxer_->AppendData(kSourceId, cluster_c->data(),
cluster_c->size()));
}
@@ -668,10 +694,7 @@ TEST_F(ChunkDemuxerTest, TestClusterBeforeInfoTracks) {
ASSERT_EQ(AddId(), ChunkDemuxer::kOk);
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kVideoTrackNum, 0);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 1));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
}
@@ -687,13 +710,7 @@ TEST_F(ChunkDemuxerTest, TestEOSDuringInit) {
TEST_F(ChunkDemuxerTest, TestDecodeErrorEndOfStream) {
ASSERT_TRUE(InitDemuxer(true, true, false));
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 0);
- AddSimpleBlock(&cb, kVideoTrackNum, 0);
- AddSimpleBlock(&cb, kAudioTrackNum, 23);
- AddSimpleBlock(&cb, kVideoTrackNum, 33);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 4));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
EXPECT_CALL(host_, OnDemuxerError(PIPELINE_ERROR_DECODE));
@@ -703,13 +720,7 @@ TEST_F(ChunkDemuxerTest, TestDecodeErrorEndOfStream) {
TEST_F(ChunkDemuxerTest, TestNetworkErrorEndOfStream) {
ASSERT_TRUE(InitDemuxer(true, true, false));
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 0);
- AddSimpleBlock(&cb, kVideoTrackNum, 0);
- AddSimpleBlock(&cb, kAudioTrackNum, 23);
- AddSimpleBlock(&cb, kVideoTrackNum, 33);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 4));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
EXPECT_CALL(host_, OnDemuxerError(PIPELINE_ERROR_NETWORK));
@@ -780,21 +791,17 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWithPendingReads) {
EndOfStreamHelper end_of_stream_helper_2(demuxer_);
audio->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(32),
+ base::TimeDelta::FromMilliseconds(0),
&audio_read_done_1));
video->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(123),
+ base::TimeDelta::FromMilliseconds(1),
&video_read_done_1));
end_of_stream_helper_1.RequestReads();
end_of_stream_helper_2.RequestReads();
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 32);
- AddSimpleBlock(&cb, kVideoTrackNum, 123);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 2));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -826,20 +833,16 @@ TEST_F(ChunkDemuxerTest, TestReadsAfterEndOfStream) {
EndOfStreamHelper end_of_stream_helper_3(demuxer_);
audio->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(32),
+ base::TimeDelta::FromMilliseconds(0),
&audio_read_done_1));
video->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(123),
+ base::TimeDelta::FromMilliseconds(1),
&video_read_done_1));
end_of_stream_helper_1.RequestReads();
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 32);
- AddSimpleBlock(&cb, kVideoTrackNum, 123);
- scoped_ptr<Cluster> cluster(cb.Finish());
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 2));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -873,16 +876,8 @@ TEST_F(ChunkDemuxerTest, TestAppendingInPieces) {
int info_tracks_size = 0;
CreateInfoTracks(true, true, false, &info_tracks, &info_tracks_size);
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 32, 512);
- AddSimpleBlock(&cb, kVideoTrackNum, 123, 1024);
- scoped_ptr<Cluster> cluster_a(cb.Finish());
-
- cb.SetClusterTimecode(125);
- AddSimpleBlock(&cb, kAudioTrackNum, 125, 2048);
- AddSimpleBlock(&cb, kVideoTrackNum, 150, 2048);
- scoped_ptr<Cluster> cluster_b(cb.Finish());
+ scoped_ptr<Cluster> cluster_a(GenerateCluster(0, 4));
+ scoped_ptr<Cluster> cluster_b(GenerateCluster(68, 4));
size_t buffer_size = info_tracks_size + cluster_a->size() + cluster_b->size();
scoped_array<uint8> buffer(new uint8[buffer_size]);
@@ -906,31 +901,8 @@ TEST_F(ChunkDemuxerTest, TestAppendingInPieces) {
ASSERT_TRUE(audio);
ASSERT_TRUE(video);
- bool audio_read_done = false;
- bool video_read_done = false;
- audio->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(32),
- &audio_read_done));
-
- video->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(123),
- &video_read_done));
-
- EXPECT_TRUE(audio_read_done);
- EXPECT_TRUE(video_read_done);
-
- audio_read_done = false;
- video_read_done = false;
- audio->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(125),
- &audio_read_done));
-
- video->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(150),
- &video_read_done));
-
- EXPECT_TRUE(audio_read_done);
- EXPECT_TRUE(video_read_done);
+ GenerateExpectedReads(0, 4, audio, video);
+ GenerateExpectedReads(68, 4, audio, video);
}
TEST_F(ChunkDemuxerTest, TestWebMFile_AudioAndVideo) {
@@ -993,14 +965,7 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) {
TEST_F(ChunkDemuxerTest, TestIncrementalClusterParsing) {
ASSERT_TRUE(InitDemuxer(true, true, false));
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kAudioTrackNum, 0, 10);
- AddSimpleBlock(&cb, kVideoTrackNum, 1, 10);
- AddSimpleBlock(&cb, kVideoTrackNum, 2, 10);
- AddSimpleBlock(&cb, kAudioTrackNum, 3, 10);
- scoped_ptr<Cluster> cluster(cb.Finish());
-
+ scoped_ptr<Cluster> cluster(GenerateCluster(0, 6));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStream> video =
@@ -1042,11 +1007,11 @@ TEST_F(ChunkDemuxerTest, TestIncrementalClusterParsing) {
audio_read_done = false;
video_read_done = false;
audio->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(3),
+ base::TimeDelta::FromMilliseconds(23),
&audio_read_done));
video->Read(base::Bind(&OnReadDone,
- base::TimeDelta::FromMilliseconds(2),
+ base::TimeDelta::FromMilliseconds(34),
&video_read_done));
// Make sure the reads haven't completed yet.
@@ -1054,6 +1019,7 @@ TEST_F(ChunkDemuxerTest, TestIncrementalClusterParsing) {
EXPECT_FALSE(video_read_done);
// Append the remaining data.
+ ASSERT_LT(i, cluster->size());
ASSERT_TRUE(AppendData(cluster->data() + i, cluster->size() - i));
EXPECT_TRUE(audio_read_done);
diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc
index e0d679b..a9347ef 100644
--- a/media/filters/pipeline_integration_test.cc
+++ b/media/filters/pipeline_integration_test.cc
@@ -226,7 +226,7 @@ TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) {
// Verify audio decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192,
- base::TimeDelta::FromMilliseconds(477),
+ base::TimeDelta::FromMilliseconds(464),
base::TimeDelta::FromMilliseconds(617),
0x10CA, 19730));
}
diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc
index ed1e94e..8271899 100644
--- a/media/webm/webm_cluster_parser.cc
+++ b/media/webm/webm_cluster_parser.cc
@@ -19,16 +19,14 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale,
const uint8* video_encryption_key_id,
int video_encryption_key_id_size)
: timecode_multiplier_(timecode_scale / 1000.0),
- audio_track_num_(audio_track_num),
- audio_default_duration_(audio_default_duration),
- video_track_num_(video_track_num),
- video_default_duration_(video_default_duration),
video_encryption_key_id_size_(video_encryption_key_id_size),
parser_(kWebMIdCluster, this),
last_block_timecode_(-1),
block_data_size_(-1),
block_duration_(-1),
- cluster_timecode_(-1) {
+ cluster_timecode_(-1),
+ audio_(audio_track_num, audio_default_duration),
+ video_(video_track_num, video_default_duration) {
CHECK_GE(video_encryption_key_id_size, 0);
if (video_encryption_key_id_size > 0) {
video_encryption_key_id_.reset(new uint8[video_encryption_key_id_size]);
@@ -40,16 +38,16 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale,
WebMClusterParser::~WebMClusterParser() {}
void WebMClusterParser::Reset() {
- audio_buffers_.clear();
- video_buffers_.clear();
last_block_timecode_ = -1;
cluster_timecode_ = -1;
parser_.Reset();
+ audio_.Reset();
+ video_.Reset();
}
int WebMClusterParser::Parse(const uint8* buf, int size) {
- audio_buffers_.clear();
- video_buffers_.clear();
+ audio_.ClearBufferQueue();
+ video_.ClearBufferQueue();
int result = parser_.Parse(buf, size);
@@ -166,6 +164,7 @@ bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) {
block_data_size_ = size;
return true;
}
+
bool WebMClusterParser::OnBlock(int track_num, int timecode,
int block_duration,
int flags,
@@ -196,42 +195,80 @@ bool WebMClusterParser::OnBlock(int track_num, int timecode,
scoped_refptr<StreamParserBuffer> buffer =
StreamParserBuffer::CopyFrom(data, size, is_keyframe);
- if (track_num == video_track_num_ && video_encryption_key_id_.get()) {
+ if (track_num == video_.track_num() && video_encryption_key_id_.get()) {
buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
video_encryption_key_id_.get(), video_encryption_key_id_size_)));
}
buffer->SetTimestamp(timestamp);
- BufferQueue* queue = NULL;
- base::TimeDelta duration = kNoTimestamp();
-
- if (track_num == audio_track_num_) {
- duration = audio_default_duration_;
- queue = &audio_buffers_;
- } else if (track_num == video_track_num_) {
- duration = video_default_duration_;
- queue = &video_buffers_;
- } else {
- DVLOG(1) << "Unexpected track number " << track_num;
- return false;
- }
if (block_duration >= 0) {
- duration = base::TimeDelta::FromMicroseconds(
- block_duration * timecode_multiplier_);
+ buffer->SetDuration(base::TimeDelta::FromMicroseconds(
+ block_duration * timecode_multiplier_));
}
- buffer->SetDuration(duration);
+ if (track_num == audio_.track_num()) {
+ return audio_.AddBuffer(buffer);
+ } else if (track_num == video_.track_num()) {
+ return video_.AddBuffer(buffer);
+ }
+
+ DVLOG(1) << "Unexpected track number " << track_num;
+ return false;
+}
+
+WebMClusterParser::Track::Track(int track_num,
+ base::TimeDelta default_duration)
+ : track_num_(track_num),
+ default_duration_(default_duration) {
+}
+
+WebMClusterParser::Track::~Track() {}
- if (!queue->empty() &&
- buffer->GetTimestamp() == queue->back()->GetTimestamp()) {
+bool WebMClusterParser::Track::AddBuffer(
+ const scoped_refptr<StreamParserBuffer>& buffer) {
+ if (!buffers_.empty() &&
+ buffer->GetTimestamp() == buffers_.back()->GetTimestamp()) {
DVLOG(1) << "Got a block timecode that is not strictly monotonically "
- << "increasing for track " << track_num;
+ << "increasing for track " << track_num_;
return false;
}
- queue->push_back(buffer);
+ if (buffer->GetDuration() == kNoTimestamp())
+ buffer->SetDuration(default_duration_);
+
+ if (delayed_buffer_) {
+ // Update the duration of the delayed buffer and place it into the queue.
+ base::TimeDelta new_duration =
+ buffer->GetTimestamp() - delayed_buffer_->GetTimestamp();
+
+ if (new_duration <= base::TimeDelta())
+ return false;
+
+ delayed_buffer_->SetDuration(new_duration);
+ buffers_.push_back(delayed_buffer_);
+
+ delayed_buffer_ = NULL;
+ }
+
+ // Place the buffer in delayed buffer slot if we don't know
+ // its duration.
+ if (buffer->GetDuration() == kNoTimestamp()) {
+ delayed_buffer_ = buffer;
+ return true;
+ }
+
+ buffers_.push_back(buffer);
return true;
}
+void WebMClusterParser::Track::Reset() {
+ buffers_.clear();
+ delayed_buffer_ = NULL;
+}
+
+void WebMClusterParser::Track::ClearBufferQueue() {
+ buffers_.clear();
+}
+
} // namespace media
diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h
index 806e276..851f95c 100644
--- a/media/webm/webm_cluster_parser.h
+++ b/media/webm/webm_cluster_parser.h
@@ -38,10 +38,34 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient {
// Returns the number of bytes parsed on success.
int Parse(const uint8* buf, int size);
- const BufferQueue& audio_buffers() const { return audio_buffers_; }
- const BufferQueue& video_buffers() const { return video_buffers_; }
+ const BufferQueue& audio_buffers() const { return audio_.buffers(); }
+ const BufferQueue& video_buffers() const { return video_.buffers(); }
private:
+ // Helper class that manages per-track state.
+ class Track {
+ public:
+ Track(int track_num, base::TimeDelta default_duration);
+ ~Track();
+
+ int track_num() const { return track_num_; }
+ const BufferQueue& buffers() const { return buffers_; }
+
+ bool AddBuffer(const scoped_refptr<StreamParserBuffer>& buffer);
+
+ // Clears all buffer state.
+ void Reset();
+
+ // Clears only the |buffers_|.
+ void ClearBufferQueue();
+
+ private:
+ int track_num_;
+ base::TimeDelta default_duration_;
+ BufferQueue buffers_;
+ scoped_refptr<StreamParserBuffer> delayed_buffer_;
+ };
+
// WebMParserClient methods.
virtual WebMParserClient* OnListStart(int id) OVERRIDE;
virtual bool OnListEnd(int id) OVERRIDE;
@@ -54,10 +78,6 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient {
double timecode_multiplier_; // Multiplier used to convert timecodes into
// microseconds.
- int audio_track_num_;
- base::TimeDelta audio_default_duration_;
- int video_track_num_;
- base::TimeDelta video_default_duration_;
scoped_array<uint8> video_encryption_key_id_;
int video_encryption_key_id_size_;
@@ -69,8 +89,9 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient {
int64 block_duration_;
int64 cluster_timecode_;
- BufferQueue audio_buffers_;
- BufferQueue video_buffers_;
+
+ Track audio_;
+ Track video_;
DISALLOW_IMPLICIT_CONSTRUCTORS(WebMClusterParser);
};
diff --git a/media/webm/webm_cluster_parser_unittest.cc b/media/webm/webm_cluster_parser_unittest.cc
index d553c1d..cbf3150 100644
--- a/media/webm/webm_cluster_parser_unittest.cc
+++ b/media/webm/webm_cluster_parser_unittest.cc
@@ -38,11 +38,11 @@ struct BlockInfo {
};
const BlockInfo kDefaultBlockInfo[] = {
- { kAudioTrackNum, 0, -1, true },
- { kAudioTrackNum, 23, -1, true },
+ { kAudioTrackNum, 0, 23, true },
+ { kAudioTrackNum, 23, 23, true },
{ kVideoTrackNum, kVideoDefaultDurationInMs, kVideoDefaultDurationInMs,
true },
- { kAudioTrackNum, 46, -1, true },
+ { kAudioTrackNum, 46, 23, false },
{ kVideoTrackNum, 2 * kVideoDefaultDurationInMs, kVideoDefaultDurationInMs,
true },
};
@@ -242,7 +242,7 @@ TEST_F(WebMClusterParserTest, ParseBlockGroup) {
TEST_F(WebMClusterParserTest, ParseSimpleBlockAndBlockGroupMixture) {
const BlockInfo kBlockInfo[] = {
- { kAudioTrackNum, 0, -1, true },
+ { kAudioTrackNum, 0, 23, true },
{ kAudioTrackNum, 23, 23, false },
{ kVideoTrackNum, kVideoDefaultDurationInMs, kVideoDefaultDurationInMs,
true },
diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc
index 7aa85d5..d7ab5af 100644
--- a/media/webm/webm_tracks_parser.cc
+++ b/media/webm/webm_tracks_parser.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/string_util.h"
+#include "media/base/buffers.h"
#include "media/webm/webm_constants.h"
#include "media/webm/webm_content_encodings.h"
@@ -21,7 +22,9 @@ WebMTracksParser::WebMTracksParser(int64 timecode_scale)
track_num_(-1),
track_default_duration_(-1),
audio_track_num_(-1),
- video_track_num_(-1) {
+ audio_default_duration_(kNoTimestamp()),
+ video_track_num_(-1),
+ video_default_duration_(kNoTimestamp()) {
}
WebMTracksParser::~WebMTracksParser() {}
@@ -49,9 +52,9 @@ int WebMTracksParser::Parse(const uint8* buf, int size) {
track_num_ = -1;
track_default_duration_ = -1;
audio_track_num_ = -1;
- audio_default_duration_ = base::TimeDelta();
+ audio_default_duration_ = kNoTimestamp();
video_track_num_ = -1;
- video_default_duration_ = base::TimeDelta();
+ video_default_duration_ = kNoTimestamp();
WebMListParser parser(kWebMIdTracks, this);
int result = parser.Parse(buf, size);
@@ -95,7 +98,7 @@ bool WebMTracksParser::OnListEnd(int id) {
return false;
}
- base::TimeDelta default_duration;
+ base::TimeDelta default_duration = kNoTimestamp();
if (track_default_duration_ > 0) {
// Convert nanoseconds to base::TimeDelta.