summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-12 01:04:33 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-12 01:04:33 +0000
commit37141711d11b09cef8405c4c2384549dad316fe9 (patch)
tree82c6e743cb9b011d5e600069ebb42e4098b1ec81
parent8f92ac14a5a83d336f97317a7292394f187d5c16 (diff)
downloadchromium_src-37141711d11b09cef8405c4c2384549dad316fe9.zip
chromium_src-37141711d11b09cef8405c4c2384549dad316fe9.tar.gz
chromium_src-37141711d11b09cef8405c4c2384549dad316fe9.tar.bz2
Support encrypted audio stream in demuxer.
BUG=123421 TEST=updated media_unittest Review URL: https://chromiumcodereview.appspot.com/11088047 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161465 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/base/audio_decoder_config.cc19
-rw-r--r--media/base/audio_decoder_config.h11
-rw-r--r--media/ffmpeg/ffmpeg_common.cc3
-rw-r--r--media/filters/chunk_demuxer_unittest.cc173
-rw-r--r--media/filters/ffmpeg_audio_decoder_unittest.cc1
-rw-r--r--media/mp4/mp4_stream_parser.cc3
-rw-r--r--media/webm/webm_cluster_parser.cc42
-rw-r--r--media/webm/webm_cluster_parser.h2
-rw-r--r--media/webm/webm_cluster_parser_unittest.cc7
-rw-r--r--media/webm/webm_stream_parser.cc38
-rw-r--r--media/webm/webm_stream_parser.h3
-rw-r--r--media/webm/webm_tracks_parser.cc42
-rw-r--r--media/webm/webm_tracks_parser.h13
13 files changed, 229 insertions, 128 deletions
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index 1f259f3..bd0e6a7 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -16,7 +16,8 @@ AudioDecoderConfig::AudioDecoderConfig()
bits_per_channel_(0),
channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED),
samples_per_second_(0),
- extra_data_size_(0) {
+ extra_data_size_(0),
+ is_encrypted_(false) {
}
AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec,
@@ -24,9 +25,10 @@ AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec,
ChannelLayout channel_layout,
int samples_per_second,
const uint8* extra_data,
- size_t extra_data_size) {
+ size_t extra_data_size,
+ bool is_encrypted) {
Initialize(codec, bits_per_channel, channel_layout, samples_per_second,
- extra_data, extra_data_size, true);
+ extra_data, extra_data_size, is_encrypted, true);
}
void AudioDecoderConfig::Initialize(AudioCodec codec,
@@ -35,6 +37,7 @@ void AudioDecoderConfig::Initialize(AudioCodec codec,
int samples_per_second,
const uint8* extra_data,
size_t extra_data_size,
+ bool is_encrypted,
bool record_stats) {
CHECK((extra_data_size != 0) == (extra_data != NULL));
@@ -68,6 +71,8 @@ void AudioDecoderConfig::Initialize(AudioCodec codec,
} else {
extra_data_.reset();
}
+
+ is_encrypted_ = is_encrypted;
}
AudioDecoderConfig::~AudioDecoderConfig() {}
@@ -88,7 +93,8 @@ bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const {
(samples_per_second() == config.samples_per_second()) &&
(extra_data_size() == config.extra_data_size()) &&
(!extra_data() || !memcmp(extra_data(), config.extra_data(),
- extra_data_size())));
+ extra_data_size())) &&
+ (is_encrypted() == config.is_encrypted()));
}
void AudioDecoderConfig::CopyFrom(const AudioDecoderConfig& audio_config) {
@@ -98,6 +104,7 @@ void AudioDecoderConfig::CopyFrom(const AudioDecoderConfig& audio_config) {
audio_config.samples_per_second(),
audio_config.extra_data(),
audio_config.extra_data_size(),
+ audio_config.is_encrypted(),
false);
}
@@ -125,4 +132,8 @@ size_t AudioDecoderConfig::extra_data_size() const {
return extra_data_size_;
}
+bool AudioDecoderConfig::is_encrypted() const {
+ return is_encrypted_;
+}
+
} // namespace media
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index 5ab06c5..2bc2487 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -51,7 +51,8 @@ class MEDIA_EXPORT AudioDecoderConfig {
// |extra_data|, otherwise the memory is copied.
AudioDecoderConfig(AudioCodec codec, int bits_per_channel,
ChannelLayout channel_layout, int samples_per_second,
- const uint8* extra_data, size_t extra_data_size);
+ const uint8* extra_data, size_t extra_data_size,
+ bool is_encrypted);
~AudioDecoderConfig();
@@ -59,6 +60,7 @@ class MEDIA_EXPORT AudioDecoderConfig {
void Initialize(AudioCodec codec, int bits_per_channel,
ChannelLayout channel_layout, int samples_per_second,
const uint8* extra_data, size_t extra_data_size,
+ bool is_encrypted,
bool record_stats);
// Deep copies |audio_config|.
@@ -82,6 +84,11 @@ class MEDIA_EXPORT AudioDecoderConfig {
uint8* extra_data() const;
size_t extra_data_size() const;
+ // Whether the audio stream is potentially encrypted.
+ // Note that in a potentially encrypted audio stream, individual buffers
+ // can be encrypted or not encrypted.
+ bool is_encrypted() const;
+
private:
AudioCodec codec_;
int bits_per_channel_;
@@ -91,6 +98,8 @@ class MEDIA_EXPORT AudioDecoderConfig {
scoped_array<uint8> extra_data_;
size_t extra_data_size_;
+ bool is_encrypted_;
+
DISALLOW_COPY_AND_ASSIGN(AudioDecoderConfig);
};
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 00d91f5..973dc81 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -222,6 +222,7 @@ void AVCodecContextToAudioDecoderConfig(
samples_per_second,
codec_context->extradata,
codec_context->extradata_size,
+ false, // Not encrypted.
true);
}
@@ -291,7 +292,7 @@ void AVStreamToVideoDecoderConfig(
PixelFormatToVideoFormat(stream->codec->pix_fmt),
coded_size, visible_rect, natural_size,
stream->codec->extradata, stream->codec->extradata_size,
- false,
+ false, // Not encrypted.
true);
}
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 915bcf7..eae8f69 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::AnyNumber;
+using ::testing::Exactly;
using ::testing::InSequence;
using ::testing::NotNull;
using ::testing::Return;
@@ -32,6 +33,13 @@ static const uint8 kTracksHeader[] = {
static const int kTracksHeaderSize = sizeof(kTracksHeader);
static const int kTracksSizeOffset = 4;
+// The size of TrackEntry element in test file "webm_vorbis_track_entry" starts
+// at index 1 and spans 8 bytes.
+static const int kAudioTrackSizeOffset = 1;
+static const int kAudioTrackSizeWidth = 8;
+static const int kAudioTrackEntryHeaderSize = kAudioTrackSizeOffset +
+ kAudioTrackSizeWidth;
+
// The size of TrackEntry element in test file "webm_vp8_track_entry" starts at
// index 1 and spans 8 bytes.
static const int kVideoTrackSizeOffset = 1;
@@ -162,13 +170,14 @@ class ChunkDemuxerTest : public testing::Test {
}
void CreateInitSegment(bool has_audio, bool has_video,
- bool video_content_encoded,
+ bool is_audio_encrypted, bool is_video_encrypted,
scoped_array<uint8>* buffer,
int* size) {
scoped_refptr<DecoderBuffer> ebml_header;
scoped_refptr<DecoderBuffer> info;
scoped_refptr<DecoderBuffer> audio_track_entry;
scoped_refptr<DecoderBuffer> video_track_entry;
+ scoped_refptr<DecoderBuffer> audio_content_encodings;
scoped_refptr<DecoderBuffer> video_content_encodings;
ebml_header = ReadTestDataFile("webm_ebml_element");
@@ -180,12 +189,16 @@ class ChunkDemuxerTest : public testing::Test {
if (has_audio) {
audio_track_entry = ReadTestDataFile("webm_vorbis_track_entry");
tracks_element_size += audio_track_entry->GetDataSize();
+ if (is_audio_encrypted) {
+ audio_content_encodings = ReadTestDataFile("webm_content_encodings");
+ tracks_element_size += audio_content_encodings->GetDataSize();
+ }
}
if (has_video) {
video_track_entry = ReadTestDataFile("webm_vp8_track_entry");
tracks_element_size += video_track_entry->GetDataSize();
- if (video_content_encoded) {
+ if (is_video_encrypted) {
video_content_encodings = ReadTestDataFile("webm_content_encodings");
tracks_element_size += video_content_encodings->GetDataSize();
}
@@ -207,16 +220,28 @@ class ChunkDemuxerTest : public testing::Test {
WriteInt64(buf + kTracksSizeOffset, tracks_element_size);
buf += kTracksHeaderSize;
+ // TODO(xhwang): Simplify this! Probably have test data files that contain
+ // ContentEncodings directly instead of trying to create one at run-time.
if (has_audio) {
memcpy(buf, audio_track_entry->GetData(),
audio_track_entry->GetDataSize());
+ if (is_audio_encrypted) {
+ memcpy(buf + audio_track_entry->GetDataSize(),
+ audio_content_encodings->GetData(),
+ audio_content_encodings->GetDataSize());
+ WriteInt64(buf + kAudioTrackSizeOffset,
+ audio_track_entry->GetDataSize() +
+ audio_content_encodings->GetDataSize() -
+ kAudioTrackEntryHeaderSize);
+ buf += audio_content_encodings->GetDataSize();
+ }
buf += audio_track_entry->GetDataSize();
}
if (has_video) {
memcpy(buf, video_track_entry->GetData(),
video_track_entry->GetDataSize());
- if (video_content_encoded) {
+ if (is_video_encrypted) {
memcpy(buf + video_track_entry->GetDataSize(),
video_content_encodings->GetData(),
video_content_encodings->GetDataSize());
@@ -289,18 +314,24 @@ class ChunkDemuxerTest : public testing::Test {
return true;
}
- bool AppendInitSegment(bool has_audio, bool has_video,
- bool video_content_encoded) {
- return AppendInitSegment(kSourceId, has_audio, has_video,
- video_content_encoded);
+ bool AppendInitSegment(bool has_audio, bool has_video) {
+ return AppendInitSegmentWithSourceId(kSourceId, has_audio, has_video);
+ }
+
+ bool AppendInitSegmentWithSourceId(const std::string& source_id,
+ bool has_audio, bool has_video) {
+ return AppendInitSegmentWithEncryptedInfo(
+ source_id, has_audio, has_video, false, false);
}
- bool AppendInitSegment(const std::string& source_id,
- bool has_audio, bool has_video,
- bool video_content_encoded) {
+ bool AppendInitSegmentWithEncryptedInfo(const std::string& source_id,
+ bool has_audio, bool has_video,
+ bool is_audio_encrypted,
+ bool is_video_encrypted) {
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
- CreateInitSegment(has_audio, has_video, video_content_encoded,
+ CreateInitSegment(has_audio, has_video,
+ is_audio_encrypted, is_video_encrypted,
&info_tracks, &info_tracks_size);
return AppendData(source_id, info_tracks.get(), info_tracks_size);
}
@@ -337,8 +368,13 @@ class ChunkDemuxerTest : public testing::Test {
expected_status);
}
- bool InitDemuxer(bool has_audio, bool has_video,
- bool video_content_encoded) {
+ bool InitDemuxer(bool has_audio, bool has_video) {
+ return InitDemuxerWithEncryptionInfo(has_audio, has_video, false, false);
+ }
+
+ bool InitDemuxerWithEncryptionInfo(
+ bool has_audio, bool has_video,
+ bool is_audio_encrypted, bool is_video_encrypted) {
PipelineStatus expected_status =
(has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN;
@@ -353,7 +389,9 @@ class ChunkDemuxerTest : public testing::Test {
if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk)
return false;
- return AppendInitSegment(has_audio, has_video, video_content_encoded);
+ return AppendInitSegmentWithEncryptedInfo(
+ kSourceId, has_audio, has_video,
+ is_audio_encrypted, is_video_encrypted);
}
bool InitDemuxerAudioAndVideoSources(const std::string& audio_id,
@@ -367,8 +405,8 @@ class ChunkDemuxerTest : public testing::Test {
if (AddId(video_id, false, true) != ChunkDemuxer::kOk)
return false;
- bool success = AppendInitSegment(audio_id, true, false, false);
- success &= AppendInitSegment(video_id, false, true, false);
+ bool success = AppendInitSegmentWithSourceId(audio_id, true, false);
+ success &= AppendInitSegmentWithSourceId(video_id, false, true);
return success;
}
@@ -709,22 +747,31 @@ class ChunkDemuxerTest : public testing::Test {
};
TEST_F(ChunkDemuxerTest, TestInit) {
- // Test no streams, audio-only, video-only, and audio & video scenarios,
- // with video encrypted or not.
- for (int i = 0; i < 8; i++) {
+ // Test no streams, audio-only, video-only, and audio & video scenarios.
+ // Audio and video streams can be encrypted or not encrypted.
+ for (int i = 0; i < 16; i++) {
bool has_audio = (i & 0x1) != 0;
bool has_video = (i & 0x2) != 0;
- bool is_video_encrypted = (i & 0x4) != 0;
+ bool is_audio_encrypted = (i & 0x4) != 0;
+ bool is_video_encrypted = (i & 0x8) != 0;
// No test on invalid combination.
- if (!has_video && is_video_encrypted)
+ if ((!has_audio && is_audio_encrypted) ||
+ (!has_video && is_video_encrypted)) {
continue;
+ }
CreateNewDemuxer();
- if (has_video && is_video_encrypted)
- EXPECT_CALL(*this, NeedKeyMock(NotNull(), 16));
- ASSERT_TRUE(InitDemuxer(has_audio, has_video, is_video_encrypted));
+ if (is_audio_encrypted || is_video_encrypted) {
+ int need_key_count = (is_audio_encrypted ? 1 : 0) +
+ (is_video_encrypted ? 1 : 0);
+ EXPECT_CALL(*this, NeedKeyMock(NotNull(), 16))
+ .Times(Exactly(need_key_count));
+ }
+
+ ASSERT_TRUE(InitDemuxerWithEncryptionInfo(
+ has_audio, has_video, is_audio_encrypted, is_video_encrypted));
scoped_refptr<DemuxerStream> audio_stream =
demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -738,6 +785,8 @@ TEST_F(ChunkDemuxerTest, TestInit) {
EXPECT_EQ(44100, config.samples_per_second());
EXPECT_TRUE(config.extra_data());
EXPECT_GT(config.extra_data_size(), 0u);
+ EXPECT_EQ(is_audio_encrypted,
+ audio_stream->audio_decoder_config().is_encrypted());
} else {
EXPECT_FALSE(audio_stream);
}
@@ -768,13 +817,13 @@ TEST_F(ChunkDemuxerTest, TestShutdownBeforeAllInitSegmentsAppended) {
EXPECT_EQ(AddId("audio", true, false), ChunkDemuxer::kOk);
EXPECT_EQ(AddId("video", false, true), ChunkDemuxer::kOk);
- EXPECT_TRUE(AppendInitSegment("audio", true, false, false));
+ EXPECT_TRUE(AppendInitSegmentWithSourceId("audio", true, false));
}
// Test that Seek() completes successfully when the first cluster
// arrives.
TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> first_cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(first_cluster->data(), first_cluster->size()));
@@ -798,7 +847,7 @@ TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) {
// Test that parsing errors are handled for clusters appended after init.
TEST_F(ChunkDemuxerTest, TestErrorWhileParsingClusterAfterInit) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> first_cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(first_cluster->data(), first_cluster->size()));
@@ -810,7 +859,7 @@ TEST_F(ChunkDemuxerTest, TestErrorWhileParsingClusterAfterInit) {
// is in the middle of cluster. This is to verify that the parser
// does not reset itself on a seek.
TEST_F(ChunkDemuxerTest, TestSeekWhileParsingCluster) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -855,7 +904,7 @@ TEST_F(ChunkDemuxerTest, TestSeekWhileParsingCluster) {
TEST_F(ChunkDemuxerTest, TestAppendDataBeforeInit) {
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
- CreateInitSegment(true, true, false, &info_tracks, &info_tracks_size);
+ CreateInitSegment(true, true, false, false, &info_tracks, &info_tracks_size);
EXPECT_FALSE(demuxer_->AppendData(kSourceId, info_tracks.get(),
info_tracks_size));
@@ -863,7 +912,7 @@ TEST_F(ChunkDemuxerTest, TestAppendDataBeforeInit) {
// Make sure Read() callbacks are dispatched with the proper data.
TEST_F(ChunkDemuxerTest, TestRead) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -887,7 +936,7 @@ TEST_F(ChunkDemuxerTest, TestRead) {
}
TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -908,7 +957,7 @@ TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) {
}
TEST_F(ChunkDemuxerTest, TestNonMonotonicButAboveClusterTimecode) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> first_cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(first_cluster->data(), first_cluster->size()));
@@ -933,7 +982,7 @@ TEST_F(ChunkDemuxerTest, TestNonMonotonicButAboveClusterTimecode) {
}
TEST_F(ChunkDemuxerTest, TestBackwardsAndBeforeClusterTimecode) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> first_cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(first_cluster->data(), first_cluster->size()));
@@ -959,7 +1008,7 @@ TEST_F(ChunkDemuxerTest, TestBackwardsAndBeforeClusterTimecode) {
TEST_F(ChunkDemuxerTest, TestPerStreamMonotonicallyIncreasingTimestamps) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> first_cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(first_cluster->data(), first_cluster->size()));
@@ -1016,7 +1065,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWithNoAppend) {
}
TEST_F(ChunkDemuxerTest, TestEndOfStreamWithNoMediaAppend) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
CheckExpectedRanges("{ }");
demuxer_->EndOfStream(PIPELINE_OK);
@@ -1024,7 +1073,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWithNoMediaAppend) {
}
TEST_F(ChunkDemuxerTest, TestDecodeErrorEndOfStream) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -1036,7 +1085,7 @@ TEST_F(ChunkDemuxerTest, TestDecodeErrorEndOfStream) {
}
TEST_F(ChunkDemuxerTest, TestNetworkErrorEndOfStream) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -1100,7 +1149,7 @@ class EndOfStreamHelper {
// Make sure that all pending reads that we don't have media data for get an
// "end of stream" buffer when EndOfStream() is called.
TEST_F(ChunkDemuxerTest, TestEndOfStreamWithPendingReads) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster(GenerateCluster(0, 2));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -1142,7 +1191,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWithPendingReads) {
// Make sure that all Read() calls after we get an EndOfStream()
// call return an "end of stream" buffer.
TEST_F(ChunkDemuxerTest, TestReadsAfterEndOfStream) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster(GenerateCluster(0, 2));
ASSERT_TRUE(AppendData(cluster->data(), cluster->size()));
@@ -1188,7 +1237,7 @@ TEST_F(ChunkDemuxerTest, TestReadsAfterEndOfStream) {
}
TEST_F(ChunkDemuxerTest, TestEndOfStreamDuringCanceledSeek) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStream> video =
@@ -1245,7 +1294,7 @@ TEST_F(ChunkDemuxerTest, TestAppendingInPieces) {
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
- CreateInitSegment(true, true, false, &info_tracks, &info_tracks_size);
+ CreateInitSegment(true, true, false, false, &info_tracks, &info_tracks_size);
scoped_ptr<Cluster> cluster_a(kDefaultFirstCluster());
scoped_ptr<Cluster> cluster_b(kDefaultSecondCluster());
@@ -1349,7 +1398,7 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) {
// Verify that we output buffers before the entire cluster has been parsed.
TEST_F(ChunkDemuxerTest, TestIncrementalClusterParsing) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
ASSERT_TRUE(AppendEmptyCluster(0));
scoped_ptr<Cluster> cluster(GenerateCluster(0, 6));
@@ -1436,7 +1485,7 @@ TEST_F(ChunkDemuxerTest, TestAVHeadersWithAudioOnlyType) {
ASSERT_EQ(demuxer_->AddId(kSourceId, "audio/webm", codecs),
ChunkDemuxer::kOk);
- ASSERT_TRUE(AppendInitSegment(true, true, false));
+ ASSERT_TRUE(AppendInitSegment(true, true));
}
TEST_F(ChunkDemuxerTest, TestAVHeadersWithVideoOnlyType) {
@@ -1450,11 +1499,11 @@ TEST_F(ChunkDemuxerTest, TestAVHeadersWithVideoOnlyType) {
ASSERT_EQ(demuxer_->AddId(kSourceId, "video/webm", codecs),
ChunkDemuxer::kOk);
- ASSERT_TRUE(AppendInitSegment(true, true, false));
+ ASSERT_TRUE(AppendInitSegment(true, true));
}
TEST_F(ChunkDemuxerTest, TestMultipleHeaders) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -1465,7 +1514,7 @@ TEST_F(ChunkDemuxerTest, TestMultipleHeaders) {
ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size()));
// Append another identical initialization segment.
- ASSERT_TRUE(AppendInitSegment(true, true, false));
+ ASSERT_TRUE(AppendInitSegment(true, true));
scoped_ptr<Cluster> cluster_b(kDefaultSecondCluster());
ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size()));
@@ -1509,7 +1558,7 @@ TEST_F(ChunkDemuxerTest, TestAddIdFailures) {
// Adding an id with audio/video should fail because we already added audio.
ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit);
- ASSERT_TRUE(AppendInitSegment(audio_id, true, false, false));
+ ASSERT_TRUE(AppendInitSegmentWithSourceId(audio_id, true, false));
// Adding an id after append should fail.
ASSERT_EQ(AddId(video_id, false, true), ChunkDemuxer::kReachedIdLimit);
@@ -1563,7 +1612,7 @@ TEST_F(ChunkDemuxerTest, TestRemoveAndAddId) {
}
TEST_F(ChunkDemuxerTest, TestSeekCanceled) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -1601,7 +1650,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceled) {
}
TEST_F(ChunkDemuxerTest, TestSeekCanceledWhileWaitingForSeek) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -1708,7 +1757,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioIdOnly) {
&host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK));
ASSERT_EQ(AddId(kSourceId, true, false), ChunkDemuxer::kOk);
- ASSERT_TRUE(AppendInitSegment(true, false, false));
+ ASSERT_TRUE(AppendInitSegment(true, false));
// Test a simple cluster.
scoped_ptr<Cluster> cluster_1(GenerateSingleStreamCluster(0, 92,
@@ -1733,7 +1782,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_VideoIdOnly) {
&host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK));
ASSERT_EQ(AddId(kSourceId, false, true), ChunkDemuxer::kOk);
- ASSERT_TRUE(AppendInitSegment(false, true, false));
+ ASSERT_TRUE(AppendInitSegment(false, true));
// Test a simple cluster.
scoped_ptr<Cluster> cluster_1(GenerateSingleStreamCluster(0, 132,
@@ -1753,7 +1802,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_VideoIdOnly) {
}
TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioVideo) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
// Audio: 0 -> 23
// Video: 0 -> 33
@@ -1847,7 +1896,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioVideo) {
// over-hanging tails at the end of the ranges as this is likely due to block
// duration differences.
TEST_F(ChunkDemuxerTest, GetBufferedRanges_EndOfStream) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster_a(
GenerateSingleStreamCluster(0, 90, kAudioTrackNum, 90));
@@ -1866,7 +1915,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_EndOfStream) {
}
TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodes) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -1950,7 +1999,7 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesOutOfRange) {
}
TEST_F(ChunkDemuxerTest, TestClusterWithNoBuffers) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
// Generate and append an empty cluster beginning at 0.
ASSERT_TRUE(AppendEmptyCluster(0));
@@ -2046,7 +2095,7 @@ TEST_F(ChunkDemuxerTest, TestGetBufferedRangesBeforeInitSegment) {
TEST_F(ChunkDemuxerTest, TestEndOfStreamDuringSeek) {
InSequence s;
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster_a(kDefaultFirstCluster());
scoped_ptr<Cluster> cluster_b(kDefaultSecondCluster());
@@ -2222,7 +2271,7 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) {
}
TEST_F(ChunkDemuxerTest, TestTimestampPositiveOffset) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
ASSERT_TRUE(demuxer_->SetTimestampOffset(
kSourceId, base::TimeDelta::FromSeconds(30)));
@@ -2241,7 +2290,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampPositiveOffset) {
}
TEST_F(ChunkDemuxerTest, TestTimestampNegativeOffset) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
ASSERT_TRUE(demuxer_->SetTimestampOffset(
kSourceId, base::TimeDelta::FromSeconds(-1)));
@@ -2307,7 +2356,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetSeparateStreams) {
}
TEST_F(ChunkDemuxerTest, TestTimestampOffsetMidParse) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster = GenerateCluster(0, 2);
// Append only part of the cluster data.
@@ -2325,7 +2374,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetMidParse) {
}
TEST_F(ChunkDemuxerTest, TestDurationChange) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
static const int kStreamDuration = kDefaultDuration().InMilliseconds();
// Add data leading up to the currently set duration.
@@ -2359,7 +2408,7 @@ TEST_F(ChunkDemuxerTest, TestDurationChange) {
}
TEST_F(ChunkDemuxerTest, TestDurationChangeTimestampOffset) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
ASSERT_TRUE(demuxer_->SetTimestampOffset(kSourceId, kDefaultDuration()));
scoped_ptr<Cluster> cluster = GenerateCluster(0, 4);
@@ -2371,7 +2420,7 @@ TEST_F(ChunkDemuxerTest, TestDurationChangeTimestampOffset) {
}
TEST_F(ChunkDemuxerTest, TestEndOfStreamTruncateDuration) {
- ASSERT_TRUE(InitDemuxer(true, true, false));
+ ASSERT_TRUE(InitDemuxer(true, true));
scoped_ptr<Cluster> cluster_a(kDefaultFirstCluster());
ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size()));
diff --git a/media/filters/ffmpeg_audio_decoder_unittest.cc b/media/filters/ffmpeg_audio_decoder_unittest.cc
index 0b7d70b..38369cb 100644
--- a/media/filters/ffmpeg_audio_decoder_unittest.cc
+++ b/media/filters/ffmpeg_audio_decoder_unittest.cc
@@ -62,6 +62,7 @@ class FFmpegAudioDecoderTest : public testing::Test {
44100,
vorbis_extradata_->GetData(),
vorbis_extradata_->GetDataSize(),
+ false, // Not encrypted.
true);
}
diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc
index fc141b5..c600537 100644
--- a/media/mp4/mp4_stream_parser.cc
+++ b/media/mp4/mp4_stream_parser.cc
@@ -199,10 +199,11 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
return false;
}
+ bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
audio_config.Initialize(kCodecAAC, entry.samplesize,
aac.channel_layout(),
aac.GetOutputSamplesPerSecond(has_sbr_),
- NULL, 0, false);
+ NULL, 0, is_encrypted, false);
has_audio_ = true;
audio_track_id_ = track->header.track_id;
}
diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc
index a6867bc0..fb1c69b 100644
--- a/media/webm/webm_cluster_parser.cc
+++ b/media/webm/webm_cluster_parser.cc
@@ -26,8 +26,10 @@ static std::string GenerateCounterBlock(uint64 iv) {
WebMClusterParser::WebMClusterParser(int64 timecode_scale,
int audio_track_num,
int video_track_num,
+ const std::string& audio_encryption_key_id,
const std::string& video_encryption_key_id)
: timecode_multiplier_(timecode_scale / 1000.0),
+ audio_encryption_key_id_(audio_encryption_key_id),
video_encryption_key_id_(video_encryption_key_id),
parser_(kWebMIdCluster, this),
last_block_timecode_(-1),
@@ -198,24 +200,34 @@ bool WebMClusterParser::OnBlock(int track_num, int timecode,
return false;
}
+ Track* track = NULL;
+ std::string encryption_key_id;
+ if (track_num == audio_.track_num()) {
+ track = &audio_;
+ encryption_key_id = audio_encryption_key_id_;
+ } else if (track_num == video_.track_num()) {
+ track = &video_;
+ encryption_key_id = video_encryption_key_id_;
+ } else {
+ DVLOG(1) << "Unexpected track number " << track_num;
+ return false;
+ }
+
last_block_timecode_ = timecode;
base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
(cluster_timecode_ + timecode) * timecode_multiplier_);
- // Every encrypted Block has a signal byte and IV prepended to it. Current
- // encrypted WebM request for comments specification is here
- // http://wiki.webmproject.org/encryption/webm-encryption-rfc
- bool is_track_encrypted =
- track_num == video_.track_num() && !video_encryption_key_id_.empty();
-
// The first bit of the flags is set when the block contains only keyframes.
// http://www.matroska.org/technical/specs/index.html
bool is_keyframe = (flags & 0x80) != 0;
scoped_refptr<StreamParserBuffer> buffer =
StreamParserBuffer::CopyFrom(data, size, is_keyframe);
- if (is_track_encrypted) {
+ // Every encrypted Block has a signal byte and IV prepended to it. Current
+ // encrypted WebM request for comments specification is here
+ // http://wiki.webmproject.org/encryption/webm-encryption-rfc
+ if (!encryption_key_id.empty()) {
uint8 signal_byte = data[0];
int data_offset = sizeof(signal_byte);
@@ -227,9 +239,8 @@ bool WebMClusterParser::OnBlock(int track_num, int timecode,
if (signal_byte & kWebMFlagEncryptedFrame) {
uint64 network_iv;
memcpy(&network_iv, data + data_offset, sizeof(network_iv));
- const uint64 iv = base::NetToHost64(network_iv);
- counter_block = GenerateCounterBlock(iv);
- data_offset += sizeof(iv);
+ data_offset += sizeof(network_iv);
+ counter_block = GenerateCounterBlock(base::NetToHost64(network_iv));
}
// TODO(fgalligan): Revisit if DecryptConfig needs to be set on unencrypted
@@ -237,7 +248,7 @@ bool WebMClusterParser::OnBlock(int track_num, int timecode,
// Unencrypted frames of potentially encrypted streams currently set
// DecryptConfig.
buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
- video_encryption_key_id_,
+ encryption_key_id,
counter_block,
data_offset,
std::vector<SubsampleEntry>())));
@@ -252,14 +263,7 @@ bool WebMClusterParser::OnBlock(int track_num, int timecode,
block_duration * timecode_multiplier_));
}
- if (track_num == audio_.track_num()) {
- return audio_.AddBuffer(buffer);
- } else if (track_num == video_.track_num()) {
- return video_.AddBuffer(buffer);
- }
-
- DVLOG(1) << "Unexpected track number " << track_num;
- return false;
+ return track->AddBuffer(buffer);
}
WebMClusterParser::Track::Track(int track_num)
diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h
index 988f224..6748a28 100644
--- a/media/webm/webm_cluster_parser.h
+++ b/media/webm/webm_cluster_parser.h
@@ -22,6 +22,7 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient {
WebMClusterParser(int64 timecode_scale,
int audio_track_num,
int video_track_num,
+ const std::string& audio_encryption_key_id,
const std::string& video_encryption_key_id);
virtual ~WebMClusterParser();
@@ -74,6 +75,7 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient {
double timecode_multiplier_; // Multiplier used to convert timecodes into
// microseconds.
+ std::string audio_encryption_key_id_;
std::string video_encryption_key_id_;
WebMListParser parser_;
diff --git a/media/webm/webm_cluster_parser_unittest.cc b/media/webm/webm_cluster_parser_unittest.cc
index 3737e38..d12979f 100644
--- a/media/webm/webm_cluster_parser_unittest.cc
+++ b/media/webm/webm_cluster_parser_unittest.cc
@@ -121,13 +121,12 @@ static void AppendToEnd(const WebMClusterParser::BufferQueue& src,
}
}
-class WebMClusterParserTest : public testing::Test {
+class WebMClusterParserTest : public testing::Test {
public:
WebMClusterParserTest()
: parser_(new WebMClusterParser(kTimecodeScale,
- kAudioTrackNum,
- kVideoTrackNum,
- std::string())) {
+ kAudioTrackNum, kVideoTrackNum,
+ "", "")) {
}
protected:
diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc
index b0a18e3..2e34ed9 100644
--- a/media/webm/webm_stream_parser.cc
+++ b/media/webm/webm_stream_parser.cc
@@ -351,6 +351,25 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
return -1;
}
+ bool is_audio_encrypted = !tracks_parser.audio_encryption_key_id().empty();
+ AudioDecoderConfig audio_config;
+ if (is_audio_encrypted) {
+ const AudioDecoderConfig& original_audio_config =
+ config_helper.audio_config();
+
+ audio_config.Initialize(original_audio_config.codec(),
+ original_audio_config.bits_per_channel(),
+ original_audio_config.channel_layout(),
+ original_audio_config.samples_per_second(),
+ original_audio_config.extra_data(),
+ original_audio_config.extra_data_size(),
+ is_audio_encrypted, false);
+
+ FireNeedKey(tracks_parser.audio_encryption_key_id());
+ } else {
+ audio_config.CopyFrom(config_helper.audio_config());
+ }
+
// TODO(xhwang): Support decryption of audio (see http://crbug.com/123421).
bool is_video_encrypted = !tracks_parser.video_encryption_key_id().empty();
@@ -368,18 +387,12 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
original_video_config.extra_data_size(),
is_video_encrypted, false);
- // Fire needkey event.
- std::string key_id = tracks_parser.video_encryption_key_id();
- int key_id_size = key_id.size();
- 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(key_id_array.Pass(), key_id_size);
+ FireNeedKey(tracks_parser.video_encryption_key_id());
} else {
video_config.CopyFrom(config_helper.video_config());
}
- if (!config_cb_.Run(config_helper.audio_config(), video_config)) {
+ if (!config_cb_.Run(audio_config, video_config)) {
DVLOG(1) << "New config data isn't allowed.";
return -1;
}
@@ -388,6 +401,7 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
info_parser.timecode_scale(),
tracks_parser.audio_track_num(),
tracks_parser.video_track_num(),
+ tracks_parser.audio_encryption_key_id(),
tracks_parser.video_encryption_key_id()));
ChangeState(kParsingClusters);
@@ -455,4 +469,12 @@ int WebMStreamParser::ParseCluster(const uint8* data, int size) {
return bytes_parsed;
}
+void WebMStreamParser::FireNeedKey(const std::string& key_id) {
+ int key_id_size = key_id.size();
+ 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(key_id_array.Pass(), key_id_size);
+}
+
} // namespace media
diff --git a/media/webm/webm_stream_parser.h b/media/webm/webm_stream_parser.h
index c5d06d5..3640151 100644
--- a/media/webm/webm_stream_parser.h
+++ b/media/webm/webm_stream_parser.h
@@ -60,6 +60,9 @@ class WebMStreamParser : public StreamParser {
// Returning > 0 indicates success & the number of bytes parsed.
int ParseCluster(const uint8* data, int size);
+ // Fire needkey event through the |need_key_cb_|.
+ void FireNeedKey(const std::string& key_id);
+
State state_;
InitCB init_cb_;
NewConfigCB config_cb_;
diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc
index bf039bf..7232285 100644
--- a/media/webm/webm_tracks_parser.cc
+++ b/media/webm/webm_tracks_parser.cc
@@ -25,15 +25,6 @@ WebMTracksParser::WebMTracksParser()
WebMTracksParser::~WebMTracksParser() {}
-const std::string& WebMTracksParser::video_encryption_key_id() const {
- if (!video_content_encodings_client_.get())
- return EmptyString();
-
- DCHECK(!video_content_encodings_client_->content_encodings().empty());
- return video_content_encodings_client_->content_encodings()[0]->
- encryption_key_id();
-}
-
int WebMTracksParser::Parse(const uint8* buf, int size) {
track_type_ =-1;
track_num_ = -1;
@@ -50,7 +41,6 @@ int WebMTracksParser::Parse(const uint8* buf, int size) {
return parser.IsParsingComplete() ? result : 0;
}
-
WebMParserClient* WebMTracksParser::OnListStart(int id) {
if (id == kWebMIdContentEncodings) {
DCHECK(!track_content_encodings_client_.get());
@@ -81,23 +71,29 @@ bool WebMTracksParser::OnListEnd(int id) {
return false;
}
- if (track_type_ == kWebMTrackTypeVideo) {
- video_track_num_ = track_num_;
- if (track_content_encodings_client_.get()) {
- video_content_encodings_client_ =
- track_content_encodings_client_.Pass();
- }
- } else if (track_type_ == kWebMTrackTypeAudio) {
- audio_track_num_ = track_num_;
- if (track_content_encodings_client_.get()) {
- audio_content_encodings_client_ =
- track_content_encodings_client_.Pass();
- }
- } else {
+ if (track_type_ != kWebMTrackTypeAudio &&
+ track_type_ != kWebMTrackTypeVideo) {
DVLOG(1) << "Unexpected TrackType " << track_type_;
return false;
}
+ std::string encryption_key_id;
+ if (track_content_encodings_client_.get()) {
+ DCHECK(!track_content_encodings_client_->content_encodings().empty());
+ // If we have multiple ContentEncoding in one track. Always choose the
+ // key id in the first ContentEncoding as the key id of the track.
+ encryption_key_id = track_content_encodings_client_->
+ content_encodings()[0]->encryption_key_id();
+ }
+
+ if (track_type_ == kWebMTrackTypeAudio) {
+ audio_track_num_ = track_num_;
+ audio_encryption_key_id_ = encryption_key_id;
+ } else if (track_type_ == kWebMTrackTypeVideo) {
+ video_track_num_ = track_num_;
+ video_encryption_key_id_ = encryption_key_id;
+ }
+
track_type_ = -1;
track_num_ = -1;
track_content_encodings_client_.reset();
diff --git a/media/webm/webm_tracks_parser.h b/media/webm/webm_tracks_parser.h
index 24211ed..02d43d6 100644
--- a/media/webm/webm_tracks_parser.h
+++ b/media/webm/webm_tracks_parser.h
@@ -29,8 +29,12 @@ class WebMTracksParser : public WebMParserClient {
int64 audio_track_num() const { return audio_track_num_; }
int64 video_track_num() const { return video_track_num_; }
-
- const std::string& video_encryption_key_id() const;
+ const std::string& audio_encryption_key_id() const {
+ return audio_encryption_key_id_;
+ }
+ const std::string& video_encryption_key_id() const {
+ return video_encryption_key_id_;
+ }
private:
// WebMParserClient methods
@@ -46,10 +50,9 @@ class WebMTracksParser : public WebMParserClient {
scoped_ptr<WebMContentEncodingsClient> track_content_encodings_client_;
int64 audio_track_num_;
- scoped_ptr<WebMContentEncodingsClient> audio_content_encodings_client_;
-
int64 video_track_num_;
- scoped_ptr<WebMContentEncodingsClient> video_content_encodings_client_;
+ std::string audio_encryption_key_id_;
+ std::string video_encryption_key_id_;
DISALLOW_COPY_AND_ASSIGN(WebMTracksParser);
};