summaryrefslogtreecommitdiffstats
path: root/media/webm
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-16 00:14:37 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-16 00:14:37 +0000
commitafae0fbd3bfd2727b873af06d04ecb12a58138aa (patch)
tree8485484f69927e2389448a814b65eb19adfc188c /media/webm
parent428e8200c272439b8d540e41a425ab9078c46031 (diff)
downloadchromium_src-afae0fbd3bfd2727b873af06d04ecb12a58138aa.zip
chromium_src-afae0fbd3bfd2727b873af06d04ecb12a58138aa.tar.gz
chromium_src-afae0fbd3bfd2727b873af06d04ecb12a58138aa.tar.bz2
Add support for BlockGroup elements with BlockDuration.
BUG=127915 TEST=WebMClusterParserTest.ParseBlockGroup & WebMClusterParserTest.ParseSimpleBlockAndBlockGroupMixture. Review URL: https://chromiumcodereview.appspot.com/10391091 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137311 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/webm')
-rw-r--r--media/webm/cluster_builder.cc87
-rw-r--r--media/webm/cluster_builder.h4
-rw-r--r--media/webm/webm_cluster_parser.cc107
-rw-r--r--media/webm/webm_cluster_parser.h13
-rw-r--r--media/webm/webm_cluster_parser_unittest.cc261
-rw-r--r--media/webm/webm_parser.cc49
-rw-r--r--media/webm/webm_parser.h3
-rw-r--r--media/webm/webm_parser_unittest.cc76
8 files changed, 452 insertions, 148 deletions
diff --git a/media/webm/cluster_builder.cc b/media/webm/cluster_builder.cc
index 4c951ad..1c377a6 100644
--- a/media/webm/cluster_builder.cc
+++ b/media/webm/cluster_builder.cc
@@ -14,22 +14,36 @@ static const uint8 kClusterHeader[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cluster(size = 0)
0xE7, // Timecode ID
0x88, // timecode(size=8)
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // timecode value
};
-const int kClusterHeaderSize = sizeof(kClusterHeader);
-const int kClusterSizeOffset = 4;
-const int kClusterTimecodeOffset = 14;
-
static const uint8 kSimpleBlockHeader[] = {
0xA3, // SimpleBlock ID
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SimpleBlock(size = 0)
};
-const int kSimpleBlockHeaderSize = sizeof(kSimpleBlockHeader);
-const int kSimpleBlockSizeOffset = 1;
+static const uint8 kBlockGroupHeader[] = {
+ 0xA0, // BlockGroup ID
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BlockGroup(size = 0)
+ 0x9B, // BlockDuration ID
+ 0x88, // BlockDuration(size = 8)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // duration
+ 0xA1, // Block ID
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0)
+};
+
+enum {
+ kClusterSizeOffset = 4,
+ kClusterTimecodeOffset = 14,
-const int kInitialBufferSize = 32768;
+ kSimpleBlockSizeOffset = 1,
+
+ kBlockGroupSizeOffset = 1,
+ kBlockGroupDurationOffset = 11,
+ kBlockGroupBlockSizeOffset = 20,
+
+ kInitialBufferSize = 32768,
+};
Cluster::Cluster(scoped_array<uint8> data, int size)
: data_(data.Pass()), size_(size) {}
@@ -53,6 +67,46 @@ void ClusterBuilder::SetClusterTimecode(int64 cluster_timecode) {
void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags,
const uint8* data, int size) {
+ int block_size = size + 4;
+ int bytes_needed = sizeof(kSimpleBlockHeader) + block_size;
+ if (bytes_needed > (buffer_size_ - bytes_used_))
+ ExtendBuffer(bytes_needed);
+
+ uint8* buf = buffer_.get() + bytes_used_;
+ int block_offset = bytes_used_;
+ memcpy(buf, kSimpleBlockHeader, sizeof(kSimpleBlockHeader));
+ UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
+ buf += sizeof(kSimpleBlockHeader);
+
+ WriteBlock(buf, track_num, timecode, flags, data, size);
+
+ bytes_used_ += bytes_needed;
+}
+
+void ClusterBuilder::AddBlockGroup(int track_num, int64 timecode, int duration,
+ int flags, const uint8* data, int size) {
+ int block_size = size + 4;
+ int bytes_needed = sizeof(kBlockGroupHeader) + block_size;
+ int block_group_size = bytes_needed - 9;
+
+ if (bytes_needed > (buffer_size_ - bytes_used_))
+ ExtendBuffer(bytes_needed);
+
+ uint8* buf = buffer_.get() + bytes_used_;
+ int block_group_offset = bytes_used_;
+ memcpy(buf, kBlockGroupHeader, sizeof(kBlockGroupHeader));
+ UpdateUInt64(block_group_offset + kBlockGroupSizeOffset, block_group_size);
+ UpdateUInt64(block_group_offset + kBlockGroupDurationOffset, duration);
+ UpdateUInt64(block_group_offset + kBlockGroupBlockSizeOffset, block_size);
+ buf += sizeof(kBlockGroupHeader);
+
+ WriteBlock(buf, track_num, timecode, flags, data, size);
+
+ bytes_used_ += bytes_needed;
+}
+
+void ClusterBuilder::WriteBlock(uint8* buf, int track_num, int64 timecode,
+ int flags, const uint8* data, int size) {
DCHECK_GE(track_num, 0);
DCHECK_LE(track_num, 126);
DCHECK_GE(flags, 0);
@@ -65,24 +119,11 @@ void ClusterBuilder::AddSimpleBlock(int track_num, int64 timecode, int flags,
DCHECK_GE(timecode_delta, -32768);
DCHECK_LE(timecode_delta, 32767);
- int block_size = 4 + size;
- int bytes_needed = kSimpleBlockHeaderSize + block_size;
- if (bytes_needed > (buffer_size_ - bytes_used_))
- ExtendBuffer(bytes_needed);
-
- uint8* buf = buffer_.get() + bytes_used_;
- int block_offset = bytes_used_;
- memcpy(buf, kSimpleBlockHeader, kSimpleBlockHeaderSize);
- UpdateUInt64(block_offset + kSimpleBlockSizeOffset, block_size);
- buf += kSimpleBlockHeaderSize;
-
buf[0] = 0x80 | (track_num & 0x7F);
buf[1] = (timecode_delta >> 8) & 0xff;
buf[2] = timecode_delta & 0xff;
buf[3] = flags & 0xff;
memcpy(buf + 4, data, size);
-
- bytes_used_ += bytes_needed;
}
scoped_ptr<Cluster> ClusterBuilder::Finish() {
@@ -98,8 +139,8 @@ scoped_ptr<Cluster> ClusterBuilder::Finish() {
void ClusterBuilder::Reset() {
buffer_size_ = kInitialBufferSize;
buffer_.reset(new uint8[buffer_size_]);
- memcpy(buffer_.get(), kClusterHeader, kClusterHeaderSize);
- bytes_used_ = kClusterHeaderSize;
+ memcpy(buffer_.get(), kClusterHeader, sizeof(kClusterHeader));
+ bytes_used_ = sizeof(kClusterHeader);
cluster_timecode_ = -1;
}
diff --git a/media/webm/cluster_builder.h b/media/webm/cluster_builder.h
index 39cd0d0..2d47599 100644
--- a/media/webm/cluster_builder.h
+++ b/media/webm/cluster_builder.h
@@ -34,6 +34,8 @@ class ClusterBuilder {
void SetClusterTimecode(int64 cluster_timecode);
void AddSimpleBlock(int track_num, int64 timecode, int flags,
const uint8* data, int size);
+ void AddBlockGroup(int track_num, int64 timecode, int duration, int flags,
+ const uint8* data, int size);
scoped_ptr<Cluster> Finish();
@@ -41,6 +43,8 @@ class ClusterBuilder {
void Reset();
void ExtendBuffer(int bytes_needed);
void UpdateUInt64(int offset, int64 value);
+ void WriteBlock(uint8* buf, int track_num, int64 timecode, int flags,
+ const uint8* data, int size);
scoped_array<uint8> buffer_;
int buffer_size_;
diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc
index 68abec7..ed1e94e 100644
--- a/media/webm/webm_cluster_parser.cc
+++ b/media/webm/webm_cluster_parser.cc
@@ -26,6 +26,8 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale,
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) {
CHECK_GE(video_encryption_key_id_size, 0);
if (video_encryption_key_id_size > 0) {
@@ -68,17 +70,38 @@ int WebMClusterParser::Parse(const uint8* buf, int size) {
}
WebMParserClient* WebMClusterParser::OnListStart(int id) {
- if (id == kWebMIdCluster)
+ if (id == kWebMIdCluster) {
cluster_timecode_ = -1;
+ } else if (id == kWebMIdBlockGroup) {
+ block_data_.reset();
+ block_data_size_ = -1;
+ block_duration_ = -1;
+ }
return this;
}
bool WebMClusterParser::OnListEnd(int id) {
- if (id == kWebMIdCluster)
+ if (id == kWebMIdCluster) {
cluster_timecode_ = -1;
+ return true;
+ }
- return true;
+ if (id != kWebMIdBlockGroup)
+ return true;
+
+ // Make sure the BlockGroup actually had a Block.
+ if (block_data_size_ == -1) {
+ DVLOG(1) << "Block missing from BlockGroup.";
+ return false;
+ }
+
+ bool result = ParseBlock(block_data_.get(), block_data_size_,
+ block_duration_);
+ block_data_.reset();
+ block_data_size_ = -1;
+ block_duration_ = -1;
+ return result;
}
bool WebMClusterParser::OnUInt(int id, int64 val) {
@@ -87,26 +110,78 @@ bool WebMClusterParser::OnUInt(int id, int64 val) {
return false;
cluster_timecode_ = val;
+ } else if (id == kWebMIdBlockDuration) {
+ if (block_duration_ != -1)
+ return false;
+ block_duration_ = val;
}
return true;
}
-bool WebMClusterParser::OnSimpleBlock(int track_num, int timecode,
- int flags,
- const uint8* data, int size) {
+bool WebMClusterParser::ParseBlock(const uint8* buf, int size, int duration) {
+ if (size < 4)
+ return false;
+
+ // Return an error if the trackNum > 127. We just aren't
+ // going to support large track numbers right now.
+ if (!(buf[0] & 0x80)) {
+ DVLOG(1) << "TrackNumber over 127 not supported";
+ return false;
+ }
+
+ int track_num = buf[0] & 0x7f;
+ int timecode = buf[1] << 8 | buf[2];
+ int flags = buf[3] & 0xff;
+ int lacing = (flags >> 1) & 0x3;
+
+ if (lacing) {
+ DVLOG(1) << "Lacing " << lacing << " not supported yet.";
+ return false;
+ }
+
+ // Sign extend negative timecode offsets.
+ if (timecode & 0x8000)
+ timecode |= (-1 << 16);
+
+ const uint8* frame_data = buf + 4;
+ int frame_size = size - (frame_data - buf);
+ return OnBlock(track_num, timecode, duration, flags, frame_data, frame_size);
+}
+
+bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) {
+ if (id == kWebMIdSimpleBlock)
+ return ParseBlock(data, size, -1);
+
+ if (id != kWebMIdBlock)
+ return true;
+
+ if (block_data_.get()) {
+ DVLOG(1) << "More than 1 Block in a BlockGroup is not supported.";
+ return false;
+ }
+
+ block_data_.reset(new uint8[size]);
+ memcpy(block_data_.get(), data, size);
+ block_data_size_ = size;
+ return true;
+}
+bool WebMClusterParser::OnBlock(int track_num, int timecode,
+ int block_duration,
+ int flags,
+ const uint8* data, int size) {
if (cluster_timecode_ == -1) {
- DVLOG(1) << "Got SimpleBlock before cluster timecode.";
+ DVLOG(1) << "Got a block before cluster timecode.";
return false;
}
if (timecode < 0) {
- DVLOG(1) << "Got SimpleBlock with negative timecode offset " << timecode;
+ DVLOG(1) << "Got a block with negative timecode offset " << timecode;
return false;
}
if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
- DVLOG(1) << "Got SimpleBlock with a timecode before the previous block.";
+ DVLOG(1) << "Got a block with a timecode before the previous block.";
return false;
}
@@ -128,21 +203,29 @@ bool WebMClusterParser::OnSimpleBlock(int track_num, int timecode,
buffer->SetTimestamp(timestamp);
BufferQueue* queue = NULL;
+ base::TimeDelta duration = kNoTimestamp();
if (track_num == audio_track_num_) {
- buffer->SetDuration(audio_default_duration_);
+ duration = audio_default_duration_;
queue = &audio_buffers_;
} else if (track_num == video_track_num_) {
- buffer->SetDuration(video_default_duration_);
+ 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(duration);
+
if (!queue->empty() &&
buffer->GetTimestamp() == queue->back()->GetTimestamp()) {
- DVLOG(1) << "Got SimpleBlock timecode is not strictly monotonically "
+ DVLOG(1) << "Got a block timecode that is not strictly monotonically "
<< "increasing for track " << track_num;
return false;
}
diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h
index 1d103ff..806e276 100644
--- a/media/webm/webm_cluster_parser.h
+++ b/media/webm/webm_cluster_parser.h
@@ -9,12 +9,13 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "media/base/media_export.h"
#include "media/base/stream_parser_buffer.h"
#include "media/webm/webm_parser.h"
namespace media {
-class WebMClusterParser : public WebMParserClient {
+class MEDIA_EXPORT WebMClusterParser : public WebMParserClient {
public:
typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
@@ -45,8 +46,11 @@ class WebMClusterParser : public WebMParserClient {
virtual WebMParserClient* OnListStart(int id) OVERRIDE;
virtual bool OnListEnd(int id) OVERRIDE;
virtual bool OnUInt(int id, int64 val) OVERRIDE;
- virtual bool OnSimpleBlock(int track_num, int timecode, int flags,
- const uint8* data, int size) OVERRIDE;
+ virtual bool OnBinary(int id, const uint8* data, int size) OVERRIDE;
+
+ bool ParseBlock(const uint8* buf, int size, int duration);
+ bool OnBlock(int track_num, int timecode, int duration, int flags,
+ const uint8* data, int size);
double timecode_multiplier_; // Multiplier used to convert timecodes into
// microseconds.
@@ -60,6 +64,9 @@ class WebMClusterParser : public WebMParserClient {
WebMListParser parser_;
int64 last_block_timecode_;
+ scoped_array<uint8> block_data_;
+ int block_data_size_;
+ int64 block_duration_;
int64 cluster_timecode_;
BufferQueue audio_buffers_;
diff --git a/media/webm/webm_cluster_parser_unittest.cc b/media/webm/webm_cluster_parser_unittest.cc
new file mode 100644
index 0000000..d553c1d
--- /dev/null
+++ b/media/webm/webm_cluster_parser_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "media/webm/cluster_builder.h"
+#include "media/webm/webm_cluster_parser.h"
+#include "media/webm/webm_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::_;
+
+namespace media {
+
+enum {
+ kTimecodeScale = 1000000, // Timecode scale for millisecond timestamps.
+ kAudioTrackNum = 1,
+ kVideoTrackNum = 2,
+ kVideoDefaultDurationInMs = 33,
+};
+
+static base::TimeDelta kAudioDefaultDuration() {
+ return kNoTimestamp();
+}
+
+static base::TimeDelta kVideoDefaultDuration() {
+ return base::TimeDelta::FromMilliseconds(kVideoDefaultDurationInMs);
+}
+
+struct BlockInfo {
+ int track_num;
+ int timestamp;
+ int duration;
+ bool use_simple_block;
+};
+
+const BlockInfo kDefaultBlockInfo[] = {
+ { kAudioTrackNum, 0, -1, true },
+ { kAudioTrackNum, 23, -1, true },
+ { kVideoTrackNum, kVideoDefaultDurationInMs, kVideoDefaultDurationInMs,
+ true },
+ { kAudioTrackNum, 46, -1, true },
+ { kVideoTrackNum, 2 * kVideoDefaultDurationInMs, kVideoDefaultDurationInMs,
+ true },
+};
+
+static scoped_ptr<Cluster> CreateCluster(int timecode,
+ const BlockInfo* block_info,
+ int block_count) {
+ ClusterBuilder cb;
+ cb.SetClusterTimecode(0);
+
+ for (int i = 0; i < block_count; i++) {
+ uint8 data[] = { 0x00 };
+ if (block_info[i].use_simple_block) {
+ cb.AddSimpleBlock(block_info[i].track_num,
+ block_info[i].timestamp,
+ 0, data, sizeof(data));
+ continue;
+ }
+
+ CHECK_GE(block_info[i].duration, 0);
+ cb.AddBlockGroup(block_info[i].track_num,
+ block_info[i].timestamp,
+ block_info[i].duration,
+ 0, data, sizeof(data));
+ }
+
+ return cb.Finish();
+}
+
+static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers,
+ const WebMClusterParser::BufferQueue& video_buffers,
+ const BlockInfo* block_info,
+ int block_count) {
+ size_t audio_offset = 0;
+ size_t video_offset = 0;
+ for (int i = 0; i < block_count; i++) {
+ const WebMClusterParser::BufferQueue* buffers = NULL;
+ size_t* offset;
+
+ if (block_info[i].track_num == kAudioTrackNum) {
+ buffers = &audio_buffers;
+ offset = &audio_offset;
+ } else if (block_info[i].track_num == kVideoTrackNum) {
+ buffers = &video_buffers;
+ offset = &video_offset;
+ } else {
+ LOG(ERROR) << "Unexpected track number " << block_info[i].track_num;
+ return false;
+ }
+
+ if (*offset >= buffers->size())
+ return false;
+
+ scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++];
+
+
+ EXPECT_EQ(buffer->GetTimestamp().InMilliseconds(), block_info[i].timestamp);
+
+ if (!block_info[i].use_simple_block)
+ EXPECT_NE(buffer->GetDuration(), kNoTimestamp());
+
+ if (buffer->GetDuration() != kNoTimestamp())
+ EXPECT_EQ(buffer->GetDuration().InMilliseconds(), block_info[i].duration);
+ }
+
+ return true;
+}
+
+static bool VerifyBuffers(const scoped_ptr<WebMClusterParser>& parser,
+ const BlockInfo* block_info,
+ int block_count) {
+ return VerifyBuffers(parser->audio_buffers(),
+ parser->video_buffers(),
+ block_info,
+ block_count);
+}
+
+static void AppendToEnd(const WebMClusterParser::BufferQueue& src,
+ WebMClusterParser::BufferQueue* dest) {
+ for (WebMClusterParser::BufferQueue::const_iterator itr = src.begin();
+ itr != src.end(); ++itr) {
+ dest->push_back(*itr);
+ }
+}
+
+class WebMClusterParserTest : public testing::Test {
+ public:
+ WebMClusterParserTest()
+ : parser_(new WebMClusterParser(kTimecodeScale,
+ kAudioTrackNum,
+ kAudioDefaultDuration(),
+ kVideoTrackNum,
+ kVideoDefaultDuration(),
+ NULL, 0)) {
+ }
+
+ protected:
+ scoped_ptr<WebMClusterParser> parser_;
+};
+
+TEST_F(WebMClusterParserTest, TestReset) {
+ InSequence s;
+
+ int block_count = arraysize(kDefaultBlockInfo);
+ scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count));
+
+ // Send slightly less than the full cluster so all but the last block is
+ // parsed.
+ int result = parser_->Parse(cluster->data(), cluster->size() - 1);
+ EXPECT_GT(result, 0);
+ EXPECT_LT(result, cluster->size());
+
+ ASSERT_TRUE(VerifyBuffers(parser_, kDefaultBlockInfo, block_count - 1));
+ parser_->Reset();
+
+ // Now parse a whole cluster to verify that all the blocks will get parsed.
+ result = parser_->Parse(cluster->data(), cluster->size());
+ EXPECT_EQ(result, cluster->size());
+ ASSERT_TRUE(VerifyBuffers(parser_, kDefaultBlockInfo, block_count));
+}
+
+TEST_F(WebMClusterParserTest, ParseClusterWithSingleCall) {
+ int block_count = arraysize(kDefaultBlockInfo);
+ scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count));
+
+ int result = parser_->Parse(cluster->data(), cluster->size());
+ EXPECT_EQ(cluster->size(), result);
+ ASSERT_TRUE(VerifyBuffers(parser_, kDefaultBlockInfo, block_count));
+}
+
+TEST_F(WebMClusterParserTest, ParseClusterWithMultipleCalls) {
+ int block_count = arraysize(kDefaultBlockInfo);
+ scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count));
+
+ WebMClusterParser::BufferQueue audio_buffers;
+ WebMClusterParser::BufferQueue video_buffers;
+
+ const uint8* data = cluster->data();
+ int size = cluster->size();
+ int default_parse_size = 3;
+ int parse_size = std::min(default_parse_size, size);
+
+ while (size > 0) {
+ int result = parser_->Parse(data, parse_size);
+ ASSERT_GE(result, 0);
+ ASSERT_LE(result, parse_size);
+
+ if (result == 0) {
+ // The parser needs more data so increase the parse_size a little.
+ parse_size += default_parse_size;
+ parse_size = std::min(parse_size, size);
+ continue;
+ }
+
+ AppendToEnd(parser_->audio_buffers(), &audio_buffers);
+ AppendToEnd(parser_->video_buffers(), &video_buffers);
+
+ parse_size = default_parse_size;
+
+ data += result;
+ size -= result;
+ }
+ ASSERT_TRUE(VerifyBuffers(audio_buffers, video_buffers, kDefaultBlockInfo,
+ block_count));
+}
+
+// Verify that both BlockGroups with the BlockDuration before the Block
+// and BlockGroups with the BlockDuration after the Block are supported
+// correctly.
+// Note: Raw bytes are use here because ClusterBuilder only generates
+// one of these scenarios.
+TEST_F(WebMClusterParserTest, ParseBlockGroup) {
+ const BlockInfo kBlockInfo[] = {
+ { kAudioTrackNum, 0, 23, false },
+ { kVideoTrackNum, 33, 34, false },
+ };
+ int block_count = arraysize(kBlockInfo);
+
+ const uint8 kClusterData[] = {
+ 0x1F, 0x43, 0xB6, 0x75, 0x9B, // Cluster(size=27)
+ 0xE7, 0x81, 0x00, // Timecode(size=1, value=0)
+ // BlockGroup with BlockDuration before Block.
+ 0xA0, 0x8A, // BlockGroup(size=10)
+ 0x9B, 0x81, 0x17, // BlockDuration(size=1, value=23)
+ 0xA1, 0x85, 0x81, 0x00, 0x00, 0x00, 0xaa, // Block(size=5, track=1, ts=0)
+ // BlockGroup with BlockDuration after Block.
+ 0xA0, 0x8A, // BlockGroup(size=10)
+ 0xA1, 0x85, 0x82, 0x00, 0x21, 0x00, 0x55, // Block(size=5, track=2, ts=33)
+ 0x9B, 0x81, 0x22, // BlockDuration(size=1, value=34)
+ };
+ const int kClusterSize = sizeof(kClusterData);
+
+ int result = parser_->Parse(kClusterData, kClusterSize);
+ EXPECT_EQ(result, kClusterSize);
+ ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count));
+}
+
+TEST_F(WebMClusterParserTest, ParseSimpleBlockAndBlockGroupMixture) {
+ const BlockInfo kBlockInfo[] = {
+ { kAudioTrackNum, 0, -1, true },
+ { kAudioTrackNum, 23, 23, false },
+ { kVideoTrackNum, kVideoDefaultDurationInMs, kVideoDefaultDurationInMs,
+ true },
+ { kAudioTrackNum, 46, 23, false },
+ { kVideoTrackNum, 2 * kVideoDefaultDurationInMs, 34,
+ false },
+ };
+ int block_count = arraysize(kBlockInfo);
+ scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count));
+
+ int result = parser_->Parse(cluster->data(), cluster->size());
+ EXPECT_EQ(cluster->size(), result);
+ ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count));
+}
+
+} // namespace media
diff --git a/media/webm/webm_parser.cc b/media/webm/webm_parser.cc
index ea7eea9..28c847b 100644
--- a/media/webm/webm_parser.cc
+++ b/media/webm/webm_parser.cc
@@ -22,7 +22,6 @@ enum ElementType {
FLOAT,
BINARY,
STRING,
- SBLOCK,
SKIP,
};
@@ -97,7 +96,7 @@ static const ElementIdInfo kChapterTranslateIds[] = {
};
static const ElementIdInfo kClusterIds[] = {
- {SBLOCK, kWebMIdSimpleBlock},
+ {BINARY, kWebMIdSimpleBlock},
{UINT, kWebMIdTimecode},
{LIST, kWebMIdSilentTracks},
{UINT, kWebMIdPosition},
@@ -529,43 +528,6 @@ static int FindListLevel(int id) {
return -1;
}
-static int ParseSimpleBlock(const uint8* buf, int size,
- WebMParserClient* client) {
- if (size < 4)
- return -1;
-
- // Return an error if the trackNum > 127. We just aren't
- // going to support large track numbers right now.
- if ((buf[0] & 0x80) != 0x80) {
- DVLOG(1) << "TrackNumber over 127 not supported";
- return -1;
- }
-
- int track_num = buf[0] & 0x7f;
- int timecode = buf[1] << 8 | buf[2];
- int flags = buf[3] & 0xff;
- int lacing = (flags >> 1) & 0x3;
-
- if (lacing != 0) {
- DVLOG(1) << "Lacing " << lacing << " not supported yet.";
- return -1;
- }
-
- // Sign extend negative timecode offsets.
- if (timecode & 0x8000)
- timecode |= (-1 << 16);
-
- const uint8* frame_data = buf + 4;
- int frame_size = size - (frame_data - buf);
- if (!client->OnSimpleBlock(track_num, timecode, flags,
- frame_data, frame_size)) {
- return -1;
- }
-
- return size;
-}
-
-
static int ParseUInt(const uint8* buf, int size, int id,
WebMParserClient* client) {
if ((size <= 0) || (size > 8))
@@ -639,9 +601,6 @@ static int ParseNonListElement(ElementType type, int id, int64 element_size,
int result = -1;
switch(type) {
- case SBLOCK:
- result = ParseSimpleBlock(buf, element_size, client);
- break;
case LIST:
NOTIMPLEMENTED();
result = -1;
@@ -703,12 +662,6 @@ bool WebMParserClient::OnString(int id, const std::string& str) {
return false;
}
-bool WebMParserClient::OnSimpleBlock(int track_num, int timecode, int flags,
- const uint8* data, int size) {
- DVLOG(1) << "Unexpected simple block element";
- return false;
-}
-
WebMListParser::WebMListParser(int id, WebMParserClient* client)
: state_(NEED_LIST_HEADER),
root_id_(id),
diff --git a/media/webm/webm_parser.h b/media/webm/webm_parser.h
index 2c6d459..68611a8 100644
--- a/media/webm/webm_parser.h
+++ b/media/webm/webm_parser.h
@@ -35,9 +35,6 @@ class MEDIA_EXPORT WebMParserClient {
virtual bool OnFloat(int id, double val);
virtual bool OnBinary(int id, const uint8* data, int size);
virtual bool OnString(int id, const std::string& str);
- virtual bool OnSimpleBlock(int track_num, int timecode,
- int flags,
- const uint8* data, int size);
protected:
WebMParserClient();
diff --git a/media/webm/webm_parser_unittest.cc b/media/webm/webm_parser_unittest.cc
index e518386..4c140a6 100644
--- a/media/webm/webm_parser_unittest.cc
+++ b/media/webm/webm_parser_unittest.cc
@@ -16,6 +16,8 @@ using ::testing::_;
namespace media {
+enum { kBlockCount = 5 };
+
class MockWebMParserClient : public WebMParserClient {
public:
virtual ~MockWebMParserClient() {}
@@ -27,7 +29,6 @@ class MockWebMParserClient : public WebMParserClient {
MOCK_METHOD2(OnFloat, bool(int, double));
MOCK_METHOD3(OnBinary, bool(int, const uint8*, int));
MOCK_METHOD2(OnString, bool(int, const std::string&));
- MOCK_METHOD5(OnSimpleBlock, bool(int, int, int, const uint8*, int));
};
class WebMParserTest : public testing::Test {
@@ -35,44 +36,29 @@ class WebMParserTest : public testing::Test {
StrictMock<MockWebMParserClient> client_;
};
-struct SimpleBlockInfo {
- int track_num;
- int timestamp;
-};
-
-static void AddSimpleBlock(ClusterBuilder* cb, int track_num,
- int64 timecode) {
- uint8 data[] = { 0x00 };
- cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data));
-}
-
-static scoped_ptr<Cluster> CreateCluster(int timecode,
- const SimpleBlockInfo* block_info,
- int block_count) {
+static scoped_ptr<Cluster> CreateCluster(int block_count) {
ClusterBuilder cb;
cb.SetClusterTimecode(0);
- for (int i = 0; i < block_count; i++)
- AddSimpleBlock(&cb, block_info[i].track_num, block_info[i].timestamp);
+ for (int i = 0; i < block_count; i++) {
+ uint8 data[] = { 0x00 };
+ cb.AddSimpleBlock(0, i, 0, data, sizeof(data));
+ }
return cb.Finish();
}
-static void CreateClusterExpectations(int timecode,
- const SimpleBlockInfo* block_info,
- int block_count,
+static void CreateClusterExpectations(int block_count,
bool is_complete_cluster,
MockWebMParserClient* client) {
InSequence s;
EXPECT_CALL(*client, OnListStart(kWebMIdCluster)).WillOnce(Return(client));
- EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, timecode))
+ EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, 0))
.WillOnce(Return(true));
for (int i = 0; i < block_count; i++) {
- EXPECT_CALL(*client, OnSimpleBlock(block_info[i].track_num,
- block_info[i].timestamp,
- _, _, _))
+ EXPECT_CALL(*client, OnBinary(kWebMIdSimpleBlock, _, _))
.WillOnce(Return(true));
}
@@ -205,17 +191,8 @@ TEST_F(WebMParserTest, VoidAndCRC32InList) {
TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
- const SimpleBlockInfo kBlockInfo[] = {
- { 0, 1 },
- { 1, 2 },
- { 0, 3 },
- { 0, 4 },
- { 1, 4 },
- };
- int block_count = arraysize(kBlockInfo);
-
- scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count));
- CreateClusterExpectations(0, kBlockInfo, block_count, true, &client_);
+ scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
+ CreateClusterExpectations(kBlockCount, true, &client_);
WebMListParser parser(kWebMIdCluster, &client_);
int result = parser.Parse(cluster->data(), cluster->size());
@@ -224,17 +201,8 @@ TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
}
TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
- const SimpleBlockInfo kBlockInfo[] = {
- { 0, 1 },
- { 1, 2 },
- { 0, 3 },
- { 0, 4 },
- { 1, 4 },
- };
- int block_count = arraysize(kBlockInfo);
-
- scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count));
- CreateClusterExpectations(0, kBlockInfo, block_count, true, &client_);
+ scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
+ CreateClusterExpectations(kBlockCount, true, &client_);
const uint8* data = cluster->data();
int size = cluster->size();
@@ -267,23 +235,13 @@ TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
TEST_F(WebMParserTest, TestReset) {
InSequence s;
-
- const SimpleBlockInfo kBlockInfo[] = {
- { 0, 1 },
- { 1, 2 },
- { 0, 3 },
- { 0, 4 },
- { 1, 4 },
- };
- int block_count = arraysize(kBlockInfo);
-
- scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count));
+ scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
// First expect all but the last block.
- CreateClusterExpectations(0, kBlockInfo, block_count - 1, false, &client_);
+ CreateClusterExpectations(kBlockCount - 1, false, &client_);
// Now expect all blocks.
- CreateClusterExpectations(0, kBlockInfo, block_count, true, &client_);
+ CreateClusterExpectations(kBlockCount, true, &client_);
WebMListParser parser(kWebMIdCluster, &client_);