summaryrefslogtreecommitdiffstats
path: root/media/webm
diff options
context:
space:
mode:
authorfgalligan@chromium.org <fgalligan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-14 23:52:41 +0000
committerfgalligan@chromium.org <fgalligan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-14 23:52:41 +0000
commit4d98e445c98768bb5eb44f8947bea55c1da8334b (patch)
treeb6cf720b8d7ac51b47ab9196bbcaa7c5349977f9 /media/webm
parent76e5e6d404fa7d608a9da91e3903a9a2c9165a77 (diff)
downloadchromium_src-4d98e445c98768bb5eb44f8947bea55c1da8334b.zip
chromium_src-4d98e445c98768bb5eb44f8947bea55c1da8334b.tar.gz
chromium_src-4d98e445c98768bb5eb44f8947bea55c1da8334b.tar.bz2
Support for parsing encrypted WebM streams by src.
- Note: Only looking for comments on direction. A lot of work still needs to be done before committing. - Added support to FFmpegDemuxer to decrypt encrypted WebM streams. - Added support to FFmpegDemuxer to handle the needKey and keyAdded messages. - Added support to WebMediaPlayerImpl to handle the needKey and keyAdded messages. BUG=123426 TEST=All media_unittests pass Review URL: https://chromiumcodereview.appspot.com/10829470 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188228 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/webm')
-rw-r--r--media/webm/webm_cluster_parser.cc49
-rw-r--r--media/webm/webm_cluster_parser_unittest.cc57
-rw-r--r--media/webm/webm_crypto_helpers.cc60
-rw-r--r--media/webm/webm_crypto_helpers.h32
-rw-r--r--media/webm/webm_stream_parser.cc11
5 files changed, 159 insertions, 50 deletions
diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc
index 8a984c8..a0b95a8 100644
--- a/media/webm/webm_cluster_parser.cc
+++ b/media/webm/webm_cluster_parser.cc
@@ -10,19 +10,10 @@
#include "media/base/buffers.h"
#include "media/base/decrypt_config.h"
#include "media/webm/webm_constants.h"
+#include "media/webm/webm_crypto_helpers.h"
namespace media {
-// Generates a 16 byte CTR counter block. The CTR counter block format is a
-// CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV.
-// |iv_size| is the size of |iv| in btyes. Returns a string of
-// kDecryptionKeySize bytes.
-static std::string GenerateCounterBlock(const uint8* iv, int iv_size) {
- std::string counter_block(reinterpret_cast<const char*>(iv), iv_size);
- counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0);
- return counter_block;
-}
-
WebMClusterParser::TextTrackIterator::TextTrackIterator(
const TextTrackMap& text_track_map) :
iterator_(text_track_map.begin()),
@@ -294,39 +285,13 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num,
// encrypted WebM request for comments specification is here
// http://wiki.webmproject.org/encryption/webm-encryption-rfc
if (!encryption_key_id.empty()) {
- DCHECK_EQ(kWebMSignalByteSize, 1);
- if (size < kWebMSignalByteSize) {
- MEDIA_LOG(log_cb_)
- << "Got a block from an encrypted stream with no data.";
+ scoped_ptr<DecryptConfig> config(WebMCreateDecryptConfig(
+ data, size,
+ reinterpret_cast<const uint8*>(encryption_key_id.data()),
+ encryption_key_id.size()));
+ if (!config)
return false;
- }
- uint8 signal_byte = data[0];
- int data_offset = sizeof(signal_byte);
-
- // Setting the DecryptConfig object of the buffer while leaving the
- // initialization vector empty will tell the decryptor that the frame is
- // unencrypted.
- std::string counter_block;
-
- if (signal_byte & kWebMFlagEncryptedFrame) {
- if (size < kWebMSignalByteSize + kWebMIvSize) {
- MEDIA_LOG(log_cb_) << "Got an encrypted block with not enough data "
- << size;
- return false;
- }
- counter_block = GenerateCounterBlock(data + data_offset, kWebMIvSize);
- data_offset += kWebMIvSize;
- }
-
- // TODO(fgalligan): Revisit if DecryptConfig needs to be set on unencrypted
- // frames after the CDM API is finalized.
- // Unencrypted frames of potentially encrypted streams currently set
- // DecryptConfig.
- buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
- encryption_key_id,
- counter_block,
- data_offset,
- std::vector<SubsampleEntry>())));
+ buffer->SetDecryptConfig(config.Pass());
}
buffer->SetTimestamp(timestamp);
diff --git a/media/webm/webm_cluster_parser_unittest.cc b/media/webm/webm_cluster_parser_unittest.cc
index 07deb05..dc73329 100644
--- a/media/webm/webm_cluster_parser_unittest.cc
+++ b/media/webm/webm_cluster_parser_unittest.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "media/base/decrypt_config.h"
#include "media/webm/cluster_builder.h"
#include "media/webm/webm_cluster_parser.h"
#include "media/webm/webm_constants.h"
@@ -32,7 +33,7 @@ struct BlockInfo {
bool use_simple_block;
};
-const BlockInfo kDefaultBlockInfo[] = {
+static const BlockInfo kDefaultBlockInfo[] = {
{ kAudioTrackNum, 0, 23, true },
{ kAudioTrackNum, 23, 23, true },
{ kVideoTrackNum, 33, 34, true },
@@ -42,6 +43,11 @@ const BlockInfo kDefaultBlockInfo[] = {
{ kVideoTrackNum, 100, 33, false },
};
+static const uint8 kEncryptedFrame[] = {
+ 0x01, // Block is encrypted
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // IV
+};
+
static scoped_ptr<Cluster> CreateCluster(int timecode,
const BlockInfo* block_info,
int block_count) {
@@ -67,6 +73,18 @@ static scoped_ptr<Cluster> CreateCluster(int timecode,
return cb.Finish();
}
+// Creates a Cluster with one encrypted Block. |bytes_to_write| is number of
+// bytes of the encrypted frame to write.
+static scoped_ptr<Cluster> CreateEncryptedCluster(int bytes_to_write) {
+ CHECK_GT(bytes_to_write, 0);
+ CHECK_LE(bytes_to_write, static_cast<int>(sizeof(kEncryptedFrame)));
+
+ ClusterBuilder cb;
+ cb.SetClusterTimecode(0);
+ cb.AddSimpleBlock(kVideoTrackNum, 0, 0, kEncryptedFrame, bytes_to_write);
+ return cb.Finish();
+}
+
static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers,
const WebMClusterParser::BufferQueue& video_buffers,
const WebMClusterParser::BufferQueue& text_buffers,
@@ -165,6 +183,15 @@ static bool VerifyTextBuffers(
return true;
}
+static bool VerifyEncryptedBuffer(
+ scoped_refptr<StreamParserBuffer> buffer) {
+ EXPECT_TRUE(buffer->GetDecryptConfig());
+ EXPECT_EQ(static_cast<unsigned long>(DecryptConfig::kDecryptionKeySize),
+ buffer->GetDecryptConfig()->iv().length());
+ const uint8* data = buffer->GetData();
+ return data[0] & kWebMFlagEncryptedFrame;
+}
+
static void AppendToEnd(const WebMClusterParser::BufferQueue& src,
WebMClusterParser::BufferQueue* dest) {
for (WebMClusterParser::BufferQueue::const_iterator itr = src.begin();
@@ -440,4 +467,32 @@ TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) {
}
}
+TEST_F(WebMClusterParserTest, ParseEncryptedBlock) {
+ scoped_ptr<Cluster> cluster(CreateEncryptedCluster(sizeof(kEncryptedFrame)));
+
+ parser_.reset(new WebMClusterParser(
+ kTimecodeScale, kAudioTrackNum, kVideoTrackNum,
+ std::set<int>(),
+ std::set<int64>(), "", "video_key_id",
+ LogCB()));
+ int result = parser_->Parse(cluster->data(), cluster->size());
+ EXPECT_EQ(cluster->size(), result);
+ ASSERT_EQ(1UL, parser_->video_buffers().size());
+ scoped_refptr<StreamParserBuffer> buffer = parser_->video_buffers()[0];
+ EXPECT_TRUE(VerifyEncryptedBuffer(buffer));
+}
+
+TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) {
+ scoped_ptr<Cluster> cluster(
+ CreateEncryptedCluster(sizeof(kEncryptedFrame) - 1));
+
+ parser_.reset(new WebMClusterParser(
+ kTimecodeScale, kAudioTrackNum, kVideoTrackNum,
+ std::set<int>(),
+ std::set<int64>(), "", "video_key_id",
+ LogCB()));
+ int result = parser_->Parse(cluster->data(), cluster->size());
+ EXPECT_EQ(-1, result);
+}
+
} // namespace media
diff --git a/media/webm/webm_crypto_helpers.cc b/media/webm/webm_crypto_helpers.cc
new file mode 100644
index 0000000..ea63f87
--- /dev/null
+++ b/media/webm/webm_crypto_helpers.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2013 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_crypto_helpers.h"
+
+#include "base/logging.h"
+#include "base/sys_byteorder.h"
+#include "media/base/decrypt_config.h"
+#include "media/webm/webm_constants.h"
+
+namespace media {
+namespace {
+
+// Generates a 16 byte CTR counter block. The CTR counter block format is a
+// CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV.
+// |iv_size| is the size of |iv| in btyes. Returns a string of
+// kDecryptionKeySize bytes.
+std::string GenerateWebMCounterBlock(const uint8* iv, int iv_size) {
+ std::string counter_block(reinterpret_cast<const char*>(iv), iv_size);
+ counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0);
+ return counter_block;
+}
+
+} // namespace anonymous
+
+scoped_ptr<DecryptConfig> WebMCreateDecryptConfig(
+ const uint8* data, int data_size,
+ const uint8* key_id, int key_id_size) {
+ if (data_size < kWebMSignalByteSize) {
+ DVLOG(1) << "Got a block from an encrypted stream with no data.";
+ return scoped_ptr<DecryptConfig>(NULL);
+ }
+
+ uint8 signal_byte = data[0];
+ int frame_offset = sizeof(signal_byte);
+
+ // Setting the DecryptConfig object of the buffer while leaving the
+ // initialization vector empty will tell the decryptor that the frame is
+ // unencrypted.
+ std::string counter_block;
+
+ if (signal_byte & kWebMFlagEncryptedFrame) {
+ if (data_size < kWebMSignalByteSize + kWebMIvSize) {
+ DVLOG(1) << "Got an encrypted block with not enough data " << data_size;
+ return scoped_ptr<DecryptConfig>(NULL);
+ }
+ counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize);
+ frame_offset += kWebMIvSize;
+ }
+
+ scoped_ptr<DecryptConfig> config(new DecryptConfig(
+ std::string(reinterpret_cast<const char*>(key_id), key_id_size),
+ counter_block,
+ frame_offset,
+ std::vector<SubsampleEntry>()));
+ return config.Pass();
+}
+
+} // namespace media
diff --git a/media/webm/webm_crypto_helpers.h b/media/webm/webm_crypto_helpers.h
new file mode 100644
index 0000000..c5f1f15
--- /dev/null
+++ b/media/webm/webm_crypto_helpers.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2013 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_CRYPTO_HELPERS_H_
+#define MEDIA_WEBM_WEBM_CRYPTO_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/base/decoder_buffer.h"
+
+namespace media {
+
+// TODO(xhwang): Figure out the init data type appropriately once it's spec'ed.
+// See https://www.w3.org/Bugs/Public/show_bug.cgi?id=19096 for more
+// information.
+const char kWebMEncryptInitDataType[] = "video/webm";
+
+// Returns an initialized DecryptConfig, which can be sent to the Decryptor if
+// the stream has potentially encrypted frames. Every encrypted Block has a
+// signal byte, and if the frame is encrypted, an initialization vector
+// prepended to the frame. Leaving the IV empty will tell the decryptor that the
+// frame is unencrypted. Returns NULL if |data| is invalid. Current encrypted
+// WebM request for comments specification is here
+// http://wiki.webmproject.org/encryption/webm-encryption-rfc
+scoped_ptr<DecryptConfig> WebMCreateDecryptConfig(
+ const uint8* data, int data_size,
+ const uint8* key_id, int key_id_size);
+
+} // namespace media
+
+#endif // MEDIA_WEBM_WEBM_CRYPT_HELPERS_H_
diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc
index b60de5d..f47fa41 100644
--- a/media/webm/webm_stream_parser.cc
+++ b/media/webm/webm_stream_parser.cc
@@ -14,14 +14,12 @@
#include "media/webm/webm_cluster_parser.h"
#include "media/webm/webm_constants.h"
#include "media/webm/webm_content_encodings.h"
+#include "media/webm/webm_crypto_helpers.h"
#include "media/webm/webm_info_parser.h"
#include "media/webm/webm_tracks_parser.h"
namespace media {
-// TODO(xhwang): Figure out the init data type appropriately once it's spec'ed.
-static const char kWebMInitDataType[] = "video/webm";
-
// Helper class that uses FFmpeg to create AudioDecoderConfig &
// VideoDecoderConfig objects.
//
@@ -150,13 +148,12 @@ bool FFmpegConfigHelper::SetupStreamConfigs() {
bool no_supported_streams = true;
for (size_t i = 0; i < format_context->nb_streams; ++i) {
AVStream* stream = format_context->streams[i];
- AVCodecContext* codec_context = stream->codec;
- AVMediaType codec_type = codec_context->codec_type;
+ AVMediaType codec_type = stream->codec->codec_type;
if (codec_type == AVMEDIA_TYPE_AUDIO &&
stream->codec->codec_id == CODEC_ID_VORBIS &&
!audio_config_.IsValidConfig()) {
- AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_);
+ AVStreamToAudioDecoderConfig(stream, &audio_config_);
no_supported_streams = false;
continue;
}
@@ -473,7 +470,7 @@ void WebMStreamParser::FireNeedKey(const std::string& key_id) {
DCHECK_GT(key_id_size, 0);
scoped_array<uint8> key_id_array(new uint8[key_id_size]);
memcpy(key_id_array.get(), key_id.data(), key_id_size);
- need_key_cb_.Run(kWebMInitDataType, key_id_array.Pass(), key_id_size);
+ need_key_cb_.Run(kWebMEncryptInitDataType, key_id_array.Pass(), key_id_size);
}
} // namespace media