summaryrefslogtreecommitdiffstats
path: root/media/webm
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-24 03:50:55 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-24 03:50:55 +0000
commita5f078461ddae8dd50a68dccfbd2c31882cb62d5 (patch)
treec831d4e2a7af5f91ca21ccc1019ccbde87fe02c2 /media/webm
parenta58fec2f838877199288d1756b4ac55aeafd4794 (diff)
downloadchromium_src-a5f078461ddae8dd50a68dccfbd2c31882cb62d5.zip
chromium_src-a5f078461ddae8dd50a68dccfbd2c31882cb62d5.tar.gz
chromium_src-a5f078461ddae8dd50a68dccfbd2c31882cb62d5.tar.bz2
Add content encoding support to WebM demuxer.
BUG=none TEST=passed media_unittests Review URL: http://codereview.chromium.org/9084002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123422 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/webm')
-rw-r--r--media/webm/webm_constants.h2
-rw-r--r--media/webm/webm_content_encodings.cc19
-rw-r--r--media/webm/webm_content_encodings.h65
-rw-r--r--media/webm/webm_content_encodings_client.cc231
-rw-r--r--media/webm/webm_content_encodings_client.h40
-rw-r--r--media/webm/webm_content_encodings_client_unittest.cc201
-rw-r--r--media/webm/webm_tracks_parser.cc22
-rw-r--r--media/webm/webm_tracks_parser.h9
8 files changed, 588 insertions, 1 deletions
diff --git a/media/webm/webm_constants.h b/media/webm/webm_constants.h
index 433b31c..ecd01df 100644
--- a/media/webm/webm_constants.h
+++ b/media/webm/webm_constants.h
@@ -5,6 +5,8 @@
#ifndef MEDIA_WEBM_WEBM_CONSTANTS_H_
#define MEDIA_WEBM_WEBM_CONSTANTS_H_
+#include "base/basictypes.h"
+
namespace media {
// WebM element IDs.
diff --git a/media/webm/webm_content_encodings.cc b/media/webm/webm_content_encodings.cc
new file mode 100644
index 0000000..53cd171
--- /dev/null
+++ b/media/webm/webm_content_encodings.cc
@@ -0,0 +1,19 @@
+// 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 "media/webm/webm_content_encodings.h"
+
+namespace media {
+
+ContentEncoding::ContentEncoding()
+ : order_(kOrderInvalid),
+ scope_(kScopeInvalid),
+ type_(kTypeInvalid),
+ encryption_algo_(kEncAlgoInvalid),
+ encryption_key_id_size_(0) {
+}
+
+ContentEncoding::~ContentEncoding() {}
+
+} // namespace media
diff --git a/media/webm/webm_content_encodings.h b/media/webm/webm_content_encodings.h
new file mode 100644
index 0000000..4a5f62f
--- /dev/null
+++ b/media/webm/webm_content_encodings.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_H_
+#define MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+struct MEDIA_EXPORT ContentEncoding : public base::RefCounted<ContentEncoding> {
+ // The following enum definitions are based on the ContentEncoding element
+ // specified in the Matroska spec.
+
+ static const int kOrderInvalid = -1;
+
+ enum Scope {
+ kScopeInvalid = 0,
+ kScopeAllFrameContents = 1,
+ kScopeTrackPrivateData = 2,
+ kScopeNextContentEncodingData = 4,
+ kScopeMax = 7,
+ };
+
+ enum Type {
+ kTypeInvalid = -1,
+ kTypeCompression = 0,
+ kTypeEncryption = 1,
+ };
+
+ enum EncryptionAlgo {
+ kEncAlgoInvalid = -1,
+ kEncAlgoNotEncrypted = 0,
+ kEncAlgoDes = 1,
+ kEncAlgo3des = 2,
+ kEncAlgoTwofish = 3,
+ kEncAlgoBlowfish = 4,
+ kEncAlgoAes = 5,
+ };
+
+ ContentEncoding();
+ virtual ~ContentEncoding();
+
+ int64 order_;
+ Scope scope_;
+ Type type_;
+ EncryptionAlgo encryption_algo_;
+ scoped_array<uint8> encryption_key_id_;
+ int encryption_key_id_size_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
+};
+
+typedef std::vector<scoped_refptr<ContentEncoding> > ContentEncodings;
+
+} // namespace media
+
+#endif // MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_H_
diff --git a/media/webm/webm_content_encodings_client.cc b/media/webm/webm_content_encodings_client.cc
new file mode 100644
index 0000000..4e09ff8
--- /dev/null
+++ b/media/webm/webm_content_encodings_client.cc
@@ -0,0 +1,231 @@
+// 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 "media/webm/webm_content_encodings_client.h"
+
+#include "base/logging.h"
+#include "media/webm/webm_constants.h"
+
+namespace media {
+
+WebMContentEncodingsClient::WebMContentEncodingsClient()
+ : content_encryption_encountered_(false) {
+}
+
+WebMContentEncodingsClient::~WebMContentEncodingsClient() {}
+
+const ContentEncodings& WebMContentEncodingsClient::content_encodings() const {
+ return content_encodings_;
+}
+
+WebMParserClient* WebMContentEncodingsClient::OnListStart(int id) {
+ if (id == kWebMIdContentEncodings) {
+ DCHECK(!cur_content_encoding_);
+ DCHECK(!content_encryption_encountered_);
+ content_encodings_.clear();
+ return this;
+ }
+
+ if (id == kWebMIdContentEncoding) {
+ DCHECK(!cur_content_encoding_);
+ DCHECK(!content_encryption_encountered_);
+ cur_content_encoding_ = new ContentEncoding;
+ return this;
+ }
+
+ if (id == kWebMIdContentEncryption) {
+ DCHECK(cur_content_encoding_);
+ if (content_encryption_encountered_) {
+ DVLOG(1) << "Unexpected multiple ContentEncryption.";
+ return NULL;
+ }
+ content_encryption_encountered_ = true;
+ return this;
+ }
+
+ // This should not happen if WebMListParser is working properly.
+ DCHECK(false);
+ return NULL;
+}
+
+// Mandatory occurrence restriction is checked in this function. Multiple
+// occurrence restriction is checked in OnUInt and OnBinary.
+bool WebMContentEncodingsClient::OnListEnd(int id) {
+ if (id == kWebMIdContentEncodings) {
+ // ContentEncoding element is mandatory. Check this!
+ if (content_encodings_.empty()) {
+ DVLOG(1) << "Missing ContentEncoding.";
+ return false;
+ }
+ return true;
+ }
+
+ if (id == kWebMIdContentEncoding) {
+ DCHECK(cur_content_encoding_);
+
+ //
+ // Specify default values to missing mandatory elements.
+ //
+
+ if (cur_content_encoding_->order_ == ContentEncoding::kOrderInvalid) {
+ // Default value of encoding order is 0, which should only be used on the
+ // first ContentEncoding.
+ if (!content_encodings_.empty()) {
+ DVLOG(1) << "Missing ContentEncodingOrder.";
+ return false;
+ }
+ cur_content_encoding_->order_ = 0;
+ }
+
+ if (cur_content_encoding_->scope_ == ContentEncoding::kScopeInvalid)
+ cur_content_encoding_->scope_ = ContentEncoding::kScopeAllFrameContents;
+
+ if (cur_content_encoding_->type_ == ContentEncoding::kTypeInvalid)
+ cur_content_encoding_->type_ = ContentEncoding::kTypeCompression;
+
+ // Check for elements valid in spec but not supported for now.
+ if (cur_content_encoding_->type_ == ContentEncoding::kTypeCompression) {
+ DVLOG(1) << "ContentCompression not supported.";
+ return false;
+ }
+
+ // Enforce mandatory elements without default values.
+ DCHECK(cur_content_encoding_->type_ == ContentEncoding::kTypeEncryption);
+ if (!content_encryption_encountered_) {
+ DVLOG(1) << "ContentEncodingType is encryption but ContentEncryption "
+ "is missing.";
+ return false;
+ }
+
+ content_encodings_.push_back(cur_content_encoding_.release());
+ content_encryption_encountered_ = false;
+ return true;
+ }
+
+ if (id == kWebMIdContentEncryption) {
+ DCHECK(cur_content_encoding_);
+ // Specify default value for elements that are not present.
+ if (cur_content_encoding_->encryption_algo_ ==
+ ContentEncoding::kEncAlgoInvalid) {
+ cur_content_encoding_->encryption_algo_ =
+ ContentEncoding::kEncAlgoNotEncrypted;
+ }
+ return true;
+ }
+
+ // This should not happen if WebMListParser is working properly.
+ DCHECK(false);
+ return false;
+}
+
+// Multiple occurrence restriction and range are checked in this function.
+// Mandatory occurrence restriction is checked in OnListEnd.
+bool WebMContentEncodingsClient::OnUInt(int id, int64 val) {
+ DCHECK(cur_content_encoding_);
+
+ if (id == kWebMIdContentEncodingOrder) {
+ if (cur_content_encoding_->order_ != ContentEncoding::kOrderInvalid) {
+ DVLOG(1) << "Unexpected multiple ContentEncodingOrder.";
+ return false;
+ }
+
+ if (val != static_cast<int64>(content_encodings_.size())) {
+ // According to the spec, encoding order starts with 0 and counts upwards.
+ DVLOG(1) << "Unexpected ContentEncodingOrder.";
+ return false;
+ }
+
+ cur_content_encoding_->order_ = val;
+ return true;
+ }
+
+ if (id == kWebMIdContentEncodingScope) {
+ if (cur_content_encoding_->scope_ != ContentEncoding::kScopeInvalid) {
+ DVLOG(1) << "Unexpected multiple ContentEncodingScope.";
+ return false;
+ }
+
+ if (val == ContentEncoding::kScopeInvalid ||
+ val > ContentEncoding::kScopeMax) {
+ DVLOG(1) << "Unexpected ContentEncodingScope.";
+ return false;
+ }
+
+ if (val & ContentEncoding::kScopeNextContentEncodingData) {
+ DVLOG(1) << "Encoded next ContentEncoding is not supported.";
+ return false;
+ }
+
+ cur_content_encoding_->scope_ = static_cast<ContentEncoding::Scope>(val);
+ return true;
+ }
+
+ if (id == kWebMIdContentEncodingType) {
+ if (cur_content_encoding_->type_ != ContentEncoding::kTypeInvalid) {
+ DVLOG(1) << "Unexpected multiple ContentEncodingType.";
+ return false;
+ }
+
+ if (val == ContentEncoding::kTypeCompression) {
+ DVLOG(1) << "ContentCompression not supported.";
+ return false;
+ }
+
+ if (val != ContentEncoding::kTypeEncryption) {
+ DVLOG(1) << "Unexpected ContentEncodingType " << val << ".";
+ return false;
+ }
+
+ cur_content_encoding_->type_ = static_cast<ContentEncoding::Type>(val);
+ return true;
+ }
+
+ if (id == kWebMIdContentEncAlgo) {
+ if (cur_content_encoding_->encryption_algo_ !=
+ ContentEncoding::kEncAlgoInvalid) {
+ DVLOG(1) << "Unexpected multiple ContentEncAlgo.";
+ return false;
+ }
+
+ if (val < ContentEncoding::kEncAlgoNotEncrypted ||
+ val > ContentEncoding::kEncAlgoAes) {
+ DVLOG(1) << "Unexpected ContentEncAlgo " << val << ".";
+ return false;
+ }
+
+ cur_content_encoding_->encryption_algo_ =
+ static_cast<ContentEncoding::EncryptionAlgo>(val);
+ return true;
+ }
+
+ // This should not happen if WebMListParser is working properly.
+ DCHECK(false);
+ return false;
+}
+
+// Multiple occurrence restriction is checked in this function. Mandatory
+// restriction is checked in OnListEnd.
+bool WebMContentEncodingsClient::OnBinary(int id, const uint8* data, int size) {
+ DCHECK(cur_content_encoding_);
+ DCHECK(data);
+ DCHECK_GT(size, 0);
+
+ if (id == kWebMIdContentEncKeyID) {
+ if (cur_content_encoding_->encryption_key_id_.get() ||
+ cur_content_encoding_->encryption_key_id_size_) {
+ DVLOG(1) << "Unexpected multiple ContentEncKeyID";
+ return false;
+ }
+ cur_content_encoding_->encryption_key_id_.reset(new uint8[size]);
+ memcpy(cur_content_encoding_->encryption_key_id_.get(), data, size);
+ cur_content_encoding_->encryption_key_id_size_ = size;
+ return true;
+ }
+
+ // This should not happen if WebMListParser is working properly.
+ DCHECK(false);
+ return false;
+}
+
+} // namespace media
diff --git a/media/webm/webm_content_encodings_client.h b/media/webm/webm_content_encodings_client.h
new file mode 100644
index 0000000..9a4c876
--- /dev/null
+++ b/media/webm/webm_content_encodings_client.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_CLIENT_H_
+#define MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_CLIENT_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/base/media_export.h"
+#include "media/webm/webm_content_encodings.h"
+#include "media/webm/webm_parser.h"
+
+namespace media {
+
+// Parser for WebM ContentEncodings element.
+class MEDIA_EXPORT WebMContentEncodingsClient : public WebMParserClient {
+ public:
+ WebMContentEncodingsClient();
+ virtual ~WebMContentEncodingsClient();
+
+ const ContentEncodings& content_encodings() const;
+
+ // WebMParserClient methods
+ virtual WebMParserClient* OnListStart(int id) OVERRIDE;
+ virtual bool OnListEnd(int id) OVERRIDE;
+ virtual bool OnUInt(int id, int64 val) OVERRIDE;
+ virtual bool OnBinary(int id, const uint8* data, int size) OVERRIDE;
+
+ private:
+ scoped_refptr<ContentEncoding> cur_content_encoding_;
+ bool content_encryption_encountered_;
+ ContentEncodings content_encodings_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMContentEncodingsClient);
+};
+
+} // namespace media
+
+#endif // MEDIA_WEBM_WEBM_CONTENT_ENCODINGS_CLIENT_H_
diff --git a/media/webm/webm_content_encodings_client_unittest.cc b/media/webm/webm_content_encodings_client_unittest.cc
new file mode 100644
index 0000000..b3e8daa
--- /dev/null
+++ b/media/webm/webm_content_encodings_client_unittest.cc
@@ -0,0 +1,201 @@
+// 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 "media/webm/webm_constants.h"
+#include "media/webm/webm_content_encodings_client.h"
+#include "media/webm/webm_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class WebMContentEncodingsClientTest : public testing::Test {
+ public:
+ WebMContentEncodingsClientTest()
+ : parser_(kWebMIdContentEncodings, &client_) {}
+
+ void ParseAndExpectToFail(const uint8* buf, int size) {
+ int result = parser_.Parse(buf, size);
+ EXPECT_EQ(-1, result);
+ const ContentEncodings content_encodings = client_.content_encodings();
+ EXPECT_TRUE(content_encodings.empty());
+ }
+
+ protected:
+ WebMContentEncodingsClient client_;
+ WebMListParser parser_;
+};
+
+TEST_F(WebMContentEncodingsClientTest, EmptyContentEncodings) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x80, // ContentEncodings (size = 0)
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+TEST_F(WebMContentEncodingsClientTest, EmptyContentEncoding) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x83, // ContentEncodings (size = 3)
+ 0x63, 0x40, 0x80, // ContentEncoding (size = 0)
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+TEST_F(WebMContentEncodingsClientTest, SingleContentEncoding) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0xA1, // ContentEncodings (size = 33)
+ 0x62, 0x40, 0x9e, // ContentEncoding (size = 30)
+ 0x50, 0x31, 0x81, 0x00, // ContentEncodingOrder (size = 1)
+ 0x50, 0x32, 0x81, 0x01, // ContentEncodingScope (size = 1)
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x8F, // ContentEncryption (size = 15)
+ 0x47, 0xE1, 0x81, 0x05, // ContentEncAlgo (size = 1)
+ 0x47, 0xE2, 0x88, // ContentEncKeyID (size = 8)
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ };
+ int size = sizeof(kContentEncodings);
+
+ int result = parser_.Parse(kContentEncodings, size);
+ ASSERT_EQ(size, result);
+ const ContentEncodings content_encodings = client_.content_encodings();
+ ASSERT_EQ(1u, content_encodings.size());
+ EXPECT_EQ(0, content_encodings[0]->order_);
+ EXPECT_EQ(ContentEncoding::kScopeAllFrameContents,
+ content_encodings[0]->scope_);
+ EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type_);
+ EXPECT_EQ(ContentEncoding::kEncAlgoAes,
+ content_encodings[0]->encryption_algo_);
+ EXPECT_TRUE(content_encodings[0]->encryption_key_id_.get());
+ EXPECT_EQ(8, content_encodings[0]->encryption_key_id_size_);
+}
+
+TEST_F(WebMContentEncodingsClientTest, MultipleContentEncoding) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0xC2, // ContentEncodings (size = 66)
+ 0x62, 0x40, 0x9e, // ContentEncoding (size = 30)
+ 0x50, 0x31, 0x81, 0x00, // ContentEncodingOrder (size = 1)
+ 0x50, 0x32, 0x81, 0x03, // ContentEncodingScope (size = 1)
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x8F, // ContentEncryption (size = 15)
+ 0x47, 0xE1, 0x81, 0x05, // ContentEncAlgo (size = 1)
+ 0x47, 0xE2, 0x88, // ContentEncKeyID (size = 8)
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0x62, 0x40, 0x9e, // ContentEncoding (size = 30)
+ 0x50, 0x31, 0x81, 0x01, // ContentEncodingOrder (size = 1)
+ 0x50, 0x32, 0x81, 0x03, // ContentEncodingScope (size = 1)
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x8F, // ContentEncryption (size = 15)
+ 0x47, 0xE1, 0x81, 0x01, // ContentEncAlgo (size = 1)
+ 0x47, 0xE2, 0x88, // ContentEncKeyID (size = 8)
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ };
+ int size = sizeof(kContentEncodings);
+
+ int result = parser_.Parse(kContentEncodings, size);
+ ASSERT_EQ(size, result);
+ const ContentEncodings content_encodings = client_.content_encodings();
+ ASSERT_EQ(2u, content_encodings.size());
+
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_EQ(i, content_encodings[i]->order_);
+ EXPECT_EQ(ContentEncoding::kScopeAllFrameContents |
+ ContentEncoding::kScopeTrackPrivateData,
+ content_encodings[i]->scope_);
+ EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[i]->type_);
+ EXPECT_EQ(!i ? ContentEncoding::kEncAlgoAes : ContentEncoding::kEncAlgoDes,
+ content_encodings[i]->encryption_algo_);
+ EXPECT_TRUE(content_encodings[i]->encryption_key_id_.get());
+ EXPECT_EQ(8, content_encodings[i]->encryption_key_id_size_);
+ }
+}
+
+TEST_F(WebMContentEncodingsClientTest, DefaultValues) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x8A, // ContentEncodings (size = 10)
+ 0x62, 0x40, 0x87, // ContentEncoding (size = 7)
+ // ContentEncodingOrder missing
+ // ContentEncodingScope missing
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x80, // ContentEncryption (size = 0)
+ // ContentEncAlgo missing
+ };
+ int size = sizeof(kContentEncodings);
+
+ int result = parser_.Parse(kContentEncodings, size);
+ ASSERT_EQ(size, result);
+ const ContentEncodings content_encodings = client_.content_encodings();
+ ASSERT_EQ(1u, content_encodings.size());
+ EXPECT_EQ(0, content_encodings[0]->order_);
+ EXPECT_EQ(ContentEncoding::kScopeAllFrameContents,
+ content_encodings[0]->scope_);
+ EXPECT_EQ(ContentEncoding::kTypeEncryption, content_encodings[0]->type_);
+ EXPECT_EQ(ContentEncoding::kEncAlgoNotEncrypted,
+ content_encodings[0]->encryption_algo_);
+ EXPECT_FALSE(content_encodings[0]->encryption_key_id_.get());
+ EXPECT_EQ(0, content_encodings[0]->encryption_key_id_size_);
+}
+
+TEST_F(WebMContentEncodingsClientTest, InvalidContentEncodingOrder) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x8E, // ContentEncodings (size = 14)
+ 0x62, 0x40, 0x8B, // ContentEncoding (size = 11)
+ 0x50, 0x31, 0x81, 0xEE, // ContentEncodingOrder (size = 1), invalid
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x80, // ContentEncryption (size = 0)
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+TEST_F(WebMContentEncodingsClientTest, InvalidContentEncodingScope) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x8E, // ContentEncodings (size = 14)
+ 0x62, 0x40, 0x8B, // ContentEncoding (size = 11)
+ 0x50, 0x32, 0x81, 0xEE, // ContentEncodingScope (size = 1), invalid
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x80, // ContentEncryption (size = 0)
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+TEST_F(WebMContentEncodingsClientTest, InvalidContentEncodingType) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x8E, // ContentEncodings (size = 14)
+ 0x62, 0x40, 0x8B, // ContentEncoding (size = 11)
+ 0x50, 0x33, 0x81, 0x00, // ContentEncodingType (size = 1), invalid
+ 0x50, 0x35, 0x80, // ContentEncryption (size = 0)
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+// ContentEncodingType is encryption but no ContentEncryption present.
+TEST_F(WebMContentEncodingsClientTest, MissingContentEncryption) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x87, // ContentEncodings (size = 7)
+ 0x62, 0x40, 0x84, // ContentEncoding (size = 4)
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ // ContentEncryption missing
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+TEST_F(WebMContentEncodingsClientTest, InvalidContentEncAlgo) {
+ const uint8 kContentEncodings[] = {
+ 0x6D, 0x80, 0x99, // ContentEncodings (size = 25)
+ 0x62, 0x40, 0x96, // ContentEncoding (size = 22)
+ 0x50, 0x33, 0x81, 0x01, // ContentEncodingType (size = 1)
+ 0x50, 0x35, 0x8F, // ContentEncryption (size = 15)
+ 0x47, 0xE1, 0x81, 0xEE, // ContentEncAlgo (size = 1), invalid
+ 0x47, 0xE2, 0x88, // ContentEncKeyID (size = 8)
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ };
+ int size = sizeof(kContentEncodings);
+ ParseAndExpectToFail(kContentEncodings, size);
+}
+
+} // media
diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc
index d340b66..9757b10 100644
--- a/media/webm/webm_tracks_parser.cc
+++ b/media/webm/webm_tracks_parser.cc
@@ -45,16 +45,28 @@ int WebMTracksParser::Parse(const uint8* buf, int size) {
WebMParserClient* WebMTracksParser::OnListStart(int id) {
+ if (id == kWebMIdContentEncodings) {
+ DCHECK(!track_content_encodings_client_.get());
+ track_content_encodings_client_.reset(new WebMContentEncodingsClient);
+ return track_content_encodings_client_->OnListStart(id);
+ }
+
if (id == kWebMIdTrackEntry) {
track_type_ = -1;
track_num_ = -1;
track_default_duration_ = -1;
+ return this;
}
return this;
}
bool WebMTracksParser::OnListEnd(int id) {
+ if (id == kWebMIdContentEncodings) {
+ DCHECK(track_content_encodings_client_.get());
+ return track_content_encodings_client_->OnListEnd(id);
+ }
+
if (id == kWebMIdTrackEntry) {
if (track_type_ == -1 || track_num_ == -1) {
DVLOG(1) << "Missing TrackEntry data"
@@ -74,9 +86,17 @@ bool WebMTracksParser::OnListEnd(int id) {
if (track_type_ == kWebMTrackTypeVideo) {
video_track_num_ = track_num_;
video_default_duration_ = default_duration;
+ if (track_content_encodings_client_.get()) {
+ video_content_encodings_ =
+ track_content_encodings_client_->content_encodings();
+ }
} else if (track_type_ == kWebMTrackTypeAudio) {
audio_track_num_ = track_num_;
audio_default_duration_ = default_duration;
+ if (track_content_encodings_client_.get()) {
+ audio_content_encodings_ =
+ track_content_encodings_client_->content_encodings();
+ }
} else {
DVLOG(1) << "Unexpected TrackType " << track_type_;
return false;
@@ -84,6 +104,8 @@ bool WebMTracksParser::OnListEnd(int id) {
track_type_ = -1;
track_num_ = -1;
+ track_content_encodings_client_.reset();
+ return true;
}
return true;
diff --git a/media/webm/webm_tracks_parser.h b/media/webm/webm_tracks_parser.h
index 5c5aeda..4626e8b 100644
--- a/media/webm/webm_tracks_parser.h
+++ b/media/webm/webm_tracks_parser.h
@@ -6,7 +6,9 @@
#define MEDIA_WEBM_WEBM_TRACKS_PARSER_H_
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "base/time.h"
+#include "media/webm/webm_content_encodings_client.h"
#include "media/webm/webm_parser.h"
namespace media {
@@ -14,7 +16,7 @@ namespace media {
// Parser for WebM Tracks element.
class WebMTracksParser : public WebMParserClient {
public:
- WebMTracksParser(int64 timecode_scale);
+ explicit WebMTracksParser(int64 timecode_scale);
virtual ~WebMTracksParser();
// Parses a WebM Tracks element in |buf|.
@@ -48,10 +50,15 @@ class WebMTracksParser : public WebMParserClient {
int64 track_type_;
int64 track_num_;
int64 track_default_duration_;
+ scoped_ptr<WebMContentEncodingsClient> track_content_encodings_client_;
+
int64 audio_track_num_;
base::TimeDelta audio_default_duration_;
+ ContentEncodings audio_content_encodings_;
+
int64 video_track_num_;
base::TimeDelta video_default_duration_;
+ ContentEncodings video_content_encodings_;
DISALLOW_IMPLICIT_CONSTRUCTORS(WebMTracksParser);
};