diff options
-rw-r--r-- | media/base/stream_parser.h | 11 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 9 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.h | 1 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_client.h | 9 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_unittest.cc | 11 | ||||
-rw-r--r-- | media/filters/pipeline_integration_test.cc | 24 | ||||
-rw-r--r-- | media/webm/webm_stream_parser.cc | 14 | ||||
-rw-r--r-- | media/webm/webm_stream_parser.h | 4 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_impl.cc | 7 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_impl.h | 1 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_proxy.cc | 14 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_proxy.h | 3 |
12 files changed, 100 insertions, 8 deletions
diff --git a/media/base/stream_parser.h b/media/base/stream_parser.h index 2d71573..ef859dc 100644 --- a/media/base/stream_parser.h +++ b/media/base/stream_parser.h @@ -9,6 +9,7 @@ #include "base/callback_forward.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/time.h" #include "media/base/media_export.h" @@ -52,6 +53,13 @@ class MEDIA_EXPORT StreamParser { // error should be signalled. typedef base::Callback<bool(const BufferQueue&)> NewBuffersCB; + // A new potentially encrypted stream has been parsed. + // First parameter - The initialization data associated with the stream. + // Second parameter - Number of bytes of the initialization data. + // Return value - True indicates that the initialization data is accepted. + // False if something was wrong with the initialization data + // and a parsing error should be signalled. + typedef base::Callback<bool(scoped_array<uint8>, int)> KeyNeededCB; // Initialize the parser with necessary callbacks. Must be called before any // data is passed to Parse(). |init_cb| will be called once enough data has @@ -60,7 +68,8 @@ class MEDIA_EXPORT StreamParser { virtual void Init(const InitCB& init_cb, const NewConfigCB& config_cb, const NewBuffersCB& audio_cb, - const NewBuffersCB& video_cb) = 0; + const NewBuffersCB& video_cb, + const KeyNeededCB& key_needed_cb) = 0; // Called when a seek occurs. This flushes the current parser state // and puts the parser in a state where it can receive data for the new seek diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 9c1a6cb..f92a79e 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -363,7 +363,8 @@ void ChunkDemuxer::Initialize(DemuxerHost* host, base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this)), base::Bind(&ChunkDemuxer::OnAudioBuffers, base::Unretained(this)), - base::Bind(&ChunkDemuxer::OnVideoBuffers, base::Unretained(this))); + base::Bind(&ChunkDemuxer::OnVideoBuffers, base::Unretained(this)), + base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this))); } client_->DemuxerOpened(this); @@ -736,4 +737,10 @@ bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { return true; } +bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data, + int init_data_size) { + client_->KeyNeeded(init_data.Pass(), init_data_size); + return true; +} + } // namespace media diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index 0a14d48..725e9ee 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -91,6 +91,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { const VideoDecoderConfig& video_config); bool OnAudioBuffers(const StreamParser::BufferQueue& buffer); bool OnVideoBuffers(const StreamParser::BufferQueue& buffer); + bool OnKeyNeeded(scoped_array<uint8> init_data, int init_data_size); base::Lock lock_; State state_; diff --git a/media/filters/chunk_demuxer_client.h b/media/filters/chunk_demuxer_client.h index 691f81e..3fbe6e3 100644 --- a/media/filters/chunk_demuxer_client.h +++ b/media/filters/chunk_demuxer_client.h @@ -1,10 +1,12 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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_FILTERS_CHUNK_DEMUXER_CLIENT_H_ #define MEDIA_FILTERS_CHUNK_DEMUXER_CLIENT_H_ +#include "base/memory/scoped_ptr.h" + namespace media { class ChunkDemuxer; @@ -19,6 +21,11 @@ class ChunkDemuxerClient { // The ChunkDemuxer passed via last DemuxerOpened() call is now // closed. Any further calls on the demuxer will result in an error. virtual void DemuxerClosed() = 0; + + // A decryption key associated with |init_data| may be needed to decrypt the + // media being demuxed before decoding. Note that the demuxing itself does not + // need decryption. + virtual void KeyNeeded(scoped_array<uint8> init_data, int init_data_size) = 0; }; } // namespace media diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index 00669f2..0e062c3 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -14,6 +14,7 @@ using ::testing::AnyNumber; using ::testing::InSequence; +using ::testing::NotNull; using ::testing::Return; using ::testing::SetArgumentPointee; using ::testing::_; @@ -77,6 +78,13 @@ class MockChunkDemuxerClient : public ChunkDemuxerClient { MOCK_METHOD1(DemuxerOpened, void(ChunkDemuxer* demuxer)); MOCK_METHOD0(DemuxerClosed, void()); + // TODO(xhwang): This is a workaround of the issue that move-only parameters + // are not supported in mocked methods. Remove this when the issue is fixed. + // See http://code.google.com/p/googletest/issues/detail?id=395 + MOCK_METHOD2(KeyNeededMock, void(const uint8* init_data, int init_data_size)); + void KeyNeeded(scoped_array<uint8> init_data, int init_data_size) { + KeyNeededMock(init_data.get(), init_data_size); + } private: DISALLOW_COPY_AND_ASSIGN(MockChunkDemuxerClient); @@ -346,6 +354,9 @@ TEST_F(ChunkDemuxerTest, TestInit) { client_.reset(new MockChunkDemuxerClient()); demuxer_ = new ChunkDemuxer(client_.get()); + if (has_video && video_content_encoded) + EXPECT_CALL(*client_, KeyNeededMock(NotNull(), 16)); + ASSERT_TRUE(InitDemuxer(has_audio, has_video, video_content_encoded)); scoped_refptr<DemuxerStream> audio_stream = diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc index 8be0aff..5a8ec0f 100644 --- a/media/filters/pipeline_integration_test.cc +++ b/media/filters/pipeline_integration_test.cc @@ -33,7 +33,14 @@ class MockMediaSource : public ChunkDemuxerClient { virtual ~MockMediaSource() {} - const std::string& url() { return url_; } + void set_decryptor(AesDecryptor* decryptor) { + decryptor_ = decryptor; + } + AesDecryptor* decryptor() const { + return decryptor_; + } + + const std::string& url() const { return url_; } void Seek(int new_position, int seek_append_size) { chunk_demuxer_->FlushData(); @@ -76,6 +83,16 @@ class MockMediaSource : public ChunkDemuxerClient { chunk_demuxer_ = NULL; } + virtual void KeyNeeded(scoped_array<uint8> init_data, int init_data_size) { + DCHECK(init_data.get()); + DCHECK_EQ(init_data_size, 16); + DCHECK(decryptor()); + // In test file bear-320x240-encrypted.webm, the decryption key is equal to + // |init_data|. + decryptor()->AddKey(init_data.get(), init_data_size, + init_data.get(), init_data_size); + } + private: std::string url_; scoped_array<uint8> file_data_; @@ -83,6 +100,7 @@ class MockMediaSource : public ChunkDemuxerClient { int current_position_; int initial_append_size_; scoped_refptr<ChunkDemuxer> chunk_demuxer_; + AesDecryptor* decryptor_; }; class PipelineIntegrationTest @@ -96,8 +114,8 @@ class PipelineIntegrationTest base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK)); - decoder_->decryptor()->AddKey(kKeyId, arraysize(kKeyId) - 1, - kKeyId, arraysize(kKeyId) - 1); + ASSERT_TRUE(decoder_.get()); + source.set_decryptor(decoder_->decryptor()); message_loop_.Run(); } diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc index 94e3256..8596368 100644 --- a/media/webm/webm_stream_parser.cc +++ b/media/webm/webm_stream_parser.cc @@ -189,18 +189,21 @@ WebMStreamParser::~WebMStreamParser() {} void WebMStreamParser::Init(const InitCB& init_cb, const NewConfigCB& config_cb, const NewBuffersCB& audio_cb, - const NewBuffersCB& video_cb) { + const NewBuffersCB& video_cb, + const KeyNeededCB& key_needed_cb) { DCHECK_EQ(state_, kWaitingForInit); DCHECK(init_cb_.is_null()); DCHECK(!init_cb.is_null()); DCHECK(!config_cb.is_null()); DCHECK(!audio_cb.is_null() || !video_cb.is_null()); + DCHECK(!key_needed_cb.is_null()); ChangeState(kParsingHeaders); init_cb_ = init_cb; config_cb_ = config_cb; audio_cb_ = audio_cb; video_cb_ = video_cb; + key_needed_cb_ = key_needed_cb; } void WebMStreamParser::Flush() { @@ -334,6 +337,15 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) { config_cb_.Run(config_helper.audio_config(),config_helper.video_config()); + // TODO(xhwang): Support decryption of audio (see http://crbug.com/123421). + if (tracks_parser.video_encryption_key_id()) { + int key_id_size = tracks_parser.video_encryption_key_id_size(); + CHECK_GT(key_id_size, 0); + scoped_array<uint8> key_id(new uint8[key_id_size]); + memcpy(key_id.get(), tracks_parser.video_encryption_key_id(), key_id_size); + key_needed_cb_.Run(key_id.Pass(), key_id_size); + } + cluster_parser_.reset(new WebMClusterParser( info_parser.timecode_scale(), tracks_parser.audio_track_num(), diff --git a/media/webm/webm_stream_parser.h b/media/webm/webm_stream_parser.h index 0311297..0d37992 100644 --- a/media/webm/webm_stream_parser.h +++ b/media/webm/webm_stream_parser.h @@ -24,7 +24,8 @@ class WebMStreamParser : public StreamParser { // StreamParser implementation. virtual void Init(const InitCB& init_cb, const NewConfigCB& config_cb, const NewBuffersCB& audio_cb, - const NewBuffersCB& video_cb) OVERRIDE; + const NewBuffersCB& video_cb, + const KeyNeededCB& key_needed_cb) OVERRIDE; virtual void Flush() OVERRIDE; virtual bool Parse(const uint8* buf, int size) OVERRIDE; @@ -62,6 +63,7 @@ class WebMStreamParser : public StreamParser { NewConfigCB config_cb_; NewBuffersCB audio_cb_; NewBuffersCB video_cb_; + KeyNeededCB key_needed_cb_; scoped_ptr<WebMClusterParser> cluster_parser_; ByteQueue byte_queue_; diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc index 2f2e22b..6ebb548 100644 --- a/webkit/media/webmediaplayer_impl.cc +++ b/webkit/media/webmediaplayer_impl.cc @@ -936,6 +936,13 @@ void WebMediaPlayerImpl::OnDemuxerOpened() { GetClient()->sourceOpened(); } +void WebMediaPlayerImpl::OnKeyNeeded(scoped_array<uint8> init_data, + int init_data_size) { + DCHECK_EQ(main_loop_, MessageLoop::current()); + + GetClient()->keyNeeded("", "", init_data.get(), init_data_size); +} + void WebMediaPlayerImpl::SetOpaque(bool opaque) { DCHECK_EQ(main_loop_, MessageLoop::current()); diff --git a/webkit/media/webmediaplayer_impl.h b/webkit/media/webmediaplayer_impl.h index 83c2c0d..36a35c3 100644 --- a/webkit/media/webmediaplayer_impl.h +++ b/webkit/media/webmediaplayer_impl.h @@ -222,6 +222,7 @@ class WebMediaPlayerImpl void OnPipelineError(media::PipelineStatus error); void OnNetworkEvent(media::NetworkEvent type); void OnDemuxerOpened(); + void OnKeyNeeded(scoped_array<uint8> init_data, int init_data_size); void SetOpaque(bool); private: diff --git a/webkit/media/webmediaplayer_proxy.cc b/webkit/media/webmediaplayer_proxy.cc index 54661d9..81636d2 100644 --- a/webkit/media/webmediaplayer_proxy.cc +++ b/webkit/media/webmediaplayer_proxy.cc @@ -182,6 +182,13 @@ void WebMediaPlayerProxy::DemuxerClosed() { &WebMediaPlayerProxy::DemuxerClosedTask, this)); } +void WebMediaPlayerProxy::KeyNeeded(scoped_array<uint8> init_data, + int init_data_size) { + render_loop_->PostTask(FROM_HERE, base::Bind( + &WebMediaPlayerProxy::KeyNeededTask, this, + base::Passed(&init_data), init_data_size)); +} + void WebMediaPlayerProxy::DemuxerFlush() { if (chunk_demuxer_.get()) chunk_demuxer_->FlushData(); @@ -224,4 +231,11 @@ void WebMediaPlayerProxy::DemuxerClosedTask() { chunk_demuxer_ = NULL; } +void WebMediaPlayerProxy::KeyNeededTask(scoped_array<uint8> init_data, + int init_data_size) { + DCHECK(render_loop_->BelongsToCurrentThread()); + if (webmediaplayer_) + webmediaplayer_->OnKeyNeeded(init_data.Pass(), init_data_size); +} + } // namespace webkit_media diff --git a/webkit/media/webmediaplayer_proxy.h b/webkit/media/webmediaplayer_proxy.h index cc07306..ab1527e 100644 --- a/webkit/media/webmediaplayer_proxy.h +++ b/webkit/media/webmediaplayer_proxy.h @@ -86,6 +86,8 @@ class WebMediaPlayerProxy // ChunkDemuxerClient implementation. virtual void DemuxerOpened(media::ChunkDemuxer* demuxer) OVERRIDE; virtual void DemuxerClosed() OVERRIDE; + virtual void KeyNeeded(scoped_array<uint8> init_data, + int init_data_size) OVERRIDE; // Methods for Demuxer communication. void DemuxerFlush(); @@ -98,6 +100,7 @@ class WebMediaPlayerProxy void DemuxerOpenedTask(const scoped_refptr<media::ChunkDemuxer>& demuxer); void DemuxerClosedTask(); + void KeyNeededTask(scoped_array<uint8> init_data, int init_data_size); private: friend class base::RefCountedThreadSafe<WebMediaPlayerProxy>; |