diff options
author | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-16 00:14:37 +0000 |
---|---|---|
committer | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-16 00:14:37 +0000 |
commit | afae0fbd3bfd2727b873af06d04ecb12a58138aa (patch) | |
tree | 8485484f69927e2389448a814b65eb19adfc188c /media/webm | |
parent | 428e8200c272439b8d540e41a425ab9078c46031 (diff) | |
download | chromium_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.cc | 87 | ||||
-rw-r--r-- | media/webm/cluster_builder.h | 4 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser.cc | 107 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser.h | 13 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser_unittest.cc | 261 | ||||
-rw-r--r-- | media/webm/webm_parser.cc | 49 | ||||
-rw-r--r-- | media/webm/webm_parser.h | 3 | ||||
-rw-r--r-- | media/webm/webm_parser_unittest.cc | 76 |
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_); |