summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-29 13:13:03 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-29 13:13:03 +0000
commit6a86a4d0ec41fe9a35f08e9b18ff6cd38815e725 (patch)
treeb012c4c2c342b62db9926057122112be3bd7b426 /content/renderer
parent67212e0d0a5ef6bed95ce7e04039be08eccf35c6 (diff)
downloadchromium_src-6a86a4d0ec41fe9a35f08e9b18ff6cd38815e725.zip
chromium_src-6a86a4d0ec41fe9a35f08e9b18ff6cd38815e725.tar.gz
chromium_src-6a86a4d0ec41fe9a35f08e9b18ff6cd38815e725.tar.bz2
EME: Support ClearKey on Chrome on Android
DecryptingDemuxerStream is used in renderer process to decrypt the encrypted buffers before handling them to the browser. To the browser, the stream is just a normal clear stream. BUG=163552 TEST=Demo page works! http://downloads.webmproject.org/adaptive-encrypted-demo/adaptive/index.html Review URL: https://chromiumcodereview.appspot.com/16903004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209289 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
-rw-r--r--content/renderer/media/android/media_source_delegate.cc227
-rw-r--r--content/renderer/media/android/media_source_delegate.h53
-rw-r--r--content/renderer/media/android/webmediaplayer_android.cc11
3 files changed, 243 insertions, 48 deletions
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index ec8326c..10c8248 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -12,6 +12,7 @@
#include "media/base/demuxer_stream.h"
#include "media/base/media_log.h"
#include "media/filters/chunk_demuxer.h"
+#include "media/filters/decrypting_demuxer_stream.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebMediaSource.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
@@ -72,8 +73,9 @@ MediaSourceDelegate::MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy,
player_id_(player_id),
media_log_(media_log),
demuxer_(NULL),
- audio_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params),
- video_params_(new MediaPlayerHostMsg_ReadFromDemuxerAck_Params),
+ is_demuxer_ready_(false),
+ audio_stream_(NULL),
+ video_stream_(NULL),
seeking_(false),
last_seek_request_id_(0),
key_added_(false),
@@ -84,6 +86,10 @@ MediaSourceDelegate::~MediaSourceDelegate() {
DVLOG(1) << "~MediaSourceDelegate() : " << player_id_;
DCHECK(!chunk_demuxer_);
DCHECK(!demuxer_);
+ DCHECK(!audio_decrypting_demuxer_stream_);
+ DCHECK(!video_decrypting_demuxer_stream_);
+ DCHECK(!audio_stream_);
+ DCHECK(!video_stream_);
}
void MediaSourceDelegate::Destroy() {
@@ -99,6 +105,13 @@ void MediaSourceDelegate::Destroy() {
proxy_ = NULL;
demuxer_ = NULL;
+ audio_stream_ = NULL;
+ video_stream_ = NULL;
+ // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or
+ // before destroying them.
+ audio_decrypting_demuxer_stream_.reset();
+ video_decrypting_demuxer_stream_.reset();
+
if (chunk_demuxer_) {
chunk_demuxer_->Stop(
BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerStopDone));
@@ -108,13 +121,16 @@ void MediaSourceDelegate::Destroy() {
void MediaSourceDelegate::InitializeMediaSource(
WebKit::WebMediaSource* media_source,
const media::NeedKeyCB& need_key_cb,
+ const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
const UpdateNetworkStateCB& update_network_state_cb,
const DurationChangeCB& duration_change_cb) {
DCHECK(media_source);
media_source_.reset(media_source);
need_key_cb_ = need_key_cb;
+ set_decryptor_ready_cb_ = set_decryptor_ready_cb;
update_network_state_cb_ = update_network_state_cb;
duration_change_cb_ = duration_change_cb;
+ access_unit_size_ = kAccessUnitSizeForMediaSource;
chunk_demuxer_.reset(new media::ChunkDemuxer(
BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened),
@@ -122,10 +138,10 @@ void MediaSourceDelegate::InitializeMediaSource(
base::Bind(&MediaSourceDelegate::OnAddTextTrack,
base::Unretained(this)),
base::Bind(&LogMediaSourceError, media_log_)));
+ demuxer_ = chunk_demuxer_.get();
+
chunk_demuxer_->Initialize(this,
BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
- demuxer_ = chunk_demuxer_.get();
- access_unit_size_ = kAccessUnitSizeForMediaSource;
}
#if defined(GOOGLE_TV)
@@ -135,12 +151,12 @@ void MediaSourceDelegate::InitializeMediaStream(
DCHECK(demuxer);
demuxer_ = demuxer;
update_network_state_cb_ = update_network_state_cb;
-
- demuxer_->Initialize(this,
- BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
// When playing Media Stream, don't wait to accumulate multiple packets per
// IPC communication.
access_unit_size_ = 1;
+
+ demuxer_->Initialize(this,
+ BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
}
#endif
@@ -217,32 +233,36 @@ void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) {
// The access unit size should have been initialized properly at this stage.
DCHECK_GT(access_unit_size_, 0u);
MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params =
- type == DemuxerStream::AUDIO ? audio_params_.get() : video_params_.get();
+ type == DemuxerStream::AUDIO ? &audio_params_ : &video_params_;
params->type = type;
params->access_units.resize(access_unit_size_);
- DemuxerStream* stream = demuxer_->GetStream(type);
- DCHECK(stream != NULL);
- ReadFromDemuxerStream(stream, params, 0);
+ ReadFromDemuxerStream(type, params, 0);
}
void MediaSourceDelegate::ReadFromDemuxerStream(
- DemuxerStream* stream,
+ media::DemuxerStream::Type type,
MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
size_t index) {
DCHECK(!seeking_);
// DemuxerStream::Read() always returns the read callback asynchronously.
+ DemuxerStream* stream =
+ (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_;
stream->Read(base::Bind(&MediaSourceDelegate::OnBufferReady,
- weak_this_.GetWeakPtr(), stream, params, index));
+ weak_this_.GetWeakPtr(), type, params, index));
}
void MediaSourceDelegate::OnBufferReady(
- DemuxerStream* stream,
+ media::DemuxerStream::Type type,
MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
size_t index,
DemuxerStream::Status status,
const scoped_refptr<media::DecoderBuffer>& buffer) {
DVLOG(1) << "OnBufferReady() : " << player_id_;
+ // Drop any buffer returned during destruction.
+ if (!demuxer_)
+ return;
+
// No new OnReadFromDemuxer() will be called during seeking. So this callback
// must be from previous OnReadFromDemuxer() call and should be ignored.
if (seeking_) {
@@ -251,7 +271,7 @@ void MediaSourceDelegate::OnBufferReady(
return;
}
- bool is_audio = stream->type() == DemuxerStream::AUDIO;
+ bool is_audio = (type == DemuxerStream::AUDIO);
if (status != DemuxerStream::kAborted &&
index >= params->access_units.size()) {
LOG(ERROR) << "The internal state inconsistency onBufferReady: "
@@ -272,10 +292,12 @@ void MediaSourceDelegate::OnBufferReady(
case DemuxerStream::kConfigChanged:
// In case of kConfigChanged, need to read decoder_config once
// for the next reads.
+ // TODO(kjyoun): Investigate if we need to use this new config. See
+ // http://crbug.com/255783
if (is_audio) {
- stream->audio_decoder_config();
+ audio_stream_->audio_decoder_config();
} else {
- gfx::Size size = stream->video_decoder_config().coded_size();
+ gfx::Size size = video_stream_->video_decoder_config().coded_size();
DVLOG(1) << "Video config is changed: " << size.width() << "x"
<< size.height();
}
@@ -307,7 +329,7 @@ void MediaSourceDelegate::OnBufferReady(
// Vorbis needs 4 extra bytes padding on Android. Check
// NuMediaExtractor.cpp in Android source code.
if (is_audio && media::kCodecVorbis ==
- stream->audio_decoder_config().codec()) {
+ audio_stream_->audio_decoder_config().codec()) {
params->access_units[index].data.insert(
params->access_units[index].data.end(), kVorbisPadding,
kVorbisPadding + 4);
@@ -324,7 +346,7 @@ void MediaSourceDelegate::OnBufferReady(
buffer->GetDecryptConfig()->subsamples();
}
if (++index < params->access_units.size()) {
- ReadFromDemuxerStream(stream, params, index);
+ ReadFromDemuxerStream(type, params, index);
return;
}
break;
@@ -356,8 +378,92 @@ void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
OnDemuxerError(status);
return;
}
+
+ audio_stream_ = demuxer_->GetStream(DemuxerStream::AUDIO);
+ video_stream_ = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+ if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted()) {
+ InitAudioDecryptingDemuxerStream();
+ // InitVideoDecryptingDemuxerStream() will be called in
+ // OnAudioDecryptingDemuxerStreamInitDone().
+ return;
+ }
+
+ if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
+ InitVideoDecryptingDemuxerStream();
+ return;
+ }
+
+ // Notify demuxer ready when both streams are not encrypted.
+ is_demuxer_ready_ = true;
+ DCHECK(CanNotifyDemuxerReady());
+ NotifyDemuxerReady();
+}
+
+void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
+ DVLOG(1) << "InitAudioDecryptingDemuxerStream()";
+ audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
+ base::MessageLoopProxy::current(), set_decryptor_ready_cb_));
+ audio_decrypting_demuxer_stream_->Initialize(
+ audio_stream_,
+ BIND_TO_RENDER_LOOP(
+ &MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone));
+}
+
+void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
+ DVLOG(1) << "InitVideoDecryptingDemuxerStream()";
+ video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
+ base::MessageLoopProxy::current(), set_decryptor_ready_cb_));
+ video_decrypting_demuxer_stream_->Initialize(
+ video_stream_,
+ BIND_TO_RENDER_LOOP(
+ &MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone));
+}
+
+void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
+ media::PipelineStatus status) {
+ DVLOG(1) << "OnAudioDecryptingDemuxerStreamInitDone() : " << status;
+
+ // It is possible that this function is called after Destroy(). As a result,
+ // we need to check whether the |demuxer_| is NULL before we proceed.
+ if (!demuxer_)
+ return;
+
+ if (status != media::PIPELINE_OK)
+ audio_decrypting_demuxer_stream_.reset();
+ else
+ audio_stream_ = audio_decrypting_demuxer_stream_.get();
+
+ if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
+ InitVideoDecryptingDemuxerStream();
+ return;
+ }
+
+ // Try to notify demuxer ready when audio DDS initialization finished and
+ // video is not encrypted.
+ is_demuxer_ready_ = true;
if (CanNotifyDemuxerReady())
- NotifyDemuxerReady("");
+ NotifyDemuxerReady();
+}
+
+void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
+ media::PipelineStatus status) {
+ DVLOG(1) << "OnVideoDecryptingDemuxerStreamInitDone() : " << status;
+
+ // It is possible that this function is called after Destroy(). As a result,
+ // we need to check whether the |demuxer_| is NULL before we proceed.
+ if (!demuxer_)
+ return;
+
+ if (status != media::PIPELINE_OK)
+ video_decrypting_demuxer_stream_.reset();
+ else
+ video_stream_ = video_decrypting_demuxer_stream_.get();
+
+ // Try to notify demuxer ready when video DDS initialization finished.
+ is_demuxer_ready_ = true;
+ if (CanNotifyDemuxerReady())
+ NotifyDemuxerReady();
}
void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id,
@@ -381,9 +487,36 @@ void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id,
return;
}
+ ResetAudioDecryptingDemuxerStream();
+}
+
+void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
+ DVLOG(1) << "ResetAudioDecryptingDemuxerStream()";
+ if (audio_decrypting_demuxer_stream_) {
+ audio_decrypting_demuxer_stream_->Reset(
+ base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream,
+ weak_this_.GetWeakPtr()));
+ } else {
+ ResetVideoDecryptingDemuxerStream();
+ }
+}
+
+void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
+ DVLOG(1) << "ResetVideoDecryptingDemuxerStream()";
+ if (video_decrypting_demuxer_stream_) {
+ video_decrypting_demuxer_stream_->Reset(
+ base::Bind(&MediaSourceDelegate::SendSeekRequestAck,
+ weak_this_.GetWeakPtr()));
+ } else {
+ SendSeekRequestAck();
+ }
+}
+
+void MediaSourceDelegate::SendSeekRequestAck() {
+ DVLOG(1) << "SendSeekRequestAck()";
seeking_ = false;
+ proxy_->SeekRequestAck(player_id_, last_seek_request_id_);
last_seek_request_id_ = 0;
- proxy_->SeekRequestAck(player_id_, seek_request_id);
}
void MediaSourceDelegate::OnDemuxerStopDone() {
@@ -394,37 +527,44 @@ void MediaSourceDelegate::OnDemuxerStopDone() {
void MediaSourceDelegate::OnMediaConfigRequest() {
if (CanNotifyDemuxerReady())
- NotifyDemuxerReady("");
+ NotifyDemuxerReady();
}
void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) {
+ DVLOG(1) << "NotifyKeyAdded() : " << player_id_;
// TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady()
- // For now, we calls it when the first key is added.
+ // For now, we calls it when the first key is added. See
+ // http://crbug.com/255781
if (key_added_)
return;
key_added_ = true;
- if (CanNotifyDemuxerReady())
- NotifyDemuxerReady(key_system);
+ key_system_ = key_system;
+ if (!CanNotifyDemuxerReady())
+ return;
+ if (HasEncryptedStream())
+ NotifyDemuxerReady();
}
bool MediaSourceDelegate::CanNotifyDemuxerReady() {
- if (key_added_)
- return true;
- DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
- if (audio_stream && audio_stream->audio_decoder_config().is_encrypted())
+ // This can happen when a key is added before the demuxer is initialized.
+ // See NotifyKeyAdded().
+ // TODO(kjyoun): Remove NotifyDemxuerReady() call from NotifyKeyAdded() so
+ // that we can remove all is_demuxer_ready_/key_added_/key_system_ madness.
+ // See http://crbug.com/255781
+ if (!is_demuxer_ready_)
return false;
- DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
- if (video_stream && video_stream->video_decoder_config().is_encrypted())
+ if (HasEncryptedStream() && !key_added_)
return false;
return true;
}
-void MediaSourceDelegate::NotifyDemuxerReady(const std::string& key_system) {
+void MediaSourceDelegate::NotifyDemuxerReady() {
+ DVLOG(1) << "NotifyDemuxerReady() : " << player_id_;
+ DCHECK(CanNotifyDemuxerReady());
+
MediaPlayerHostMsg_DemuxerReady_Params params;
- DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
- if (audio_stream) {
- const media::AudioDecoderConfig& config =
- audio_stream->audio_decoder_config();
+ if (audio_stream_) {
+ media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
params.audio_codec = config.codec();
params.audio_channels =
media::ChannelLayoutToChannelCount(config.channel_layout());
@@ -433,10 +573,8 @@ void MediaSourceDelegate::NotifyDemuxerReady(const std::string& key_system) {
params.audio_extra_data = std::vector<uint8>(
config.extra_data(), config.extra_data() + config.extra_data_size());
}
- DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
- if (video_stream) {
- const media::VideoDecoderConfig& config =
- video_stream->video_decoder_config();
+ if (video_stream_) {
+ media::VideoDecoderConfig config = video_stream_->video_decoder_config();
params.video_codec = config.codec();
params.video_size = config.natural_size();
params.is_video_encrypted = config.is_encrypted();
@@ -444,7 +582,7 @@ void MediaSourceDelegate::NotifyDemuxerReady(const std::string& key_system) {
config.extra_data(), config.extra_data() + config.extra_data_size());
}
params.duration_ms = GetDurationMs();
- params.key_system = key_system;
+ params.key_system = HasEncryptedStream() ? key_system_ : "";
if (proxy_)
proxy_->DemuxerReady(player_id_, params);
@@ -488,4 +626,11 @@ scoped_ptr<media::TextTrack> MediaSourceDelegate::OnAddTextTrack(
return scoped_ptr<media::TextTrack>();
}
+bool MediaSourceDelegate::HasEncryptedStream() {
+ return (audio_stream_ &&
+ audio_stream_->audio_decoder_config().is_encrypted()) ||
+ (video_stream_ &&
+ video_stream_->video_decoder_config().is_encrypted());
+}
+
} // namespace content
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h
index a8df80b..88b9b2d 100644
--- a/content/renderer/media/android/media_source_delegate.h
+++ b/content/renderer/media/android/media_source_delegate.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
+#include "media/base/android/demuxer_stream_player_params.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer.h"
#include "media/base/media_keys.h"
@@ -21,6 +22,7 @@
namespace media {
class ChunkDemuxer;
class DecoderBuffer;
+class DecryptingDemuxerStream;
class DemuxerStream;
class MediaLog;
struct MediaPlayerHostMsg_ReadFromDemuxerAck_Params;
@@ -48,13 +50,16 @@ class MediaSourceDelegate : public media::DemuxerHost {
MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy,
int player_id,
media::MediaLog* media_log);
+
// Initialize the MediaSourceDelegate. |media_source| will be owned by
// this object after this call.
void InitializeMediaSource(
WebKit::WebMediaSource* media_source,
const media::NeedKeyCB& need_key_cb,
+ const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
const UpdateNetworkStateCB& update_network_state_cb,
const DurationChangeCB& duration_change_cb);
+
#if defined(GOOGLE_TV)
void InitializeMediaStream(
media::Demuxer* demuxer,
@@ -95,10 +100,33 @@ class MediaSourceDelegate : public media::DemuxerHost {
virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
virtual void OnDemuxerError(media::PipelineStatus status) OVERRIDE;
- // Callbacks for ChunkDemuxer.
+ // Callback for ChunkDemuxer initialization.
void OnDemuxerInitDone(media::PipelineStatus status);
+
+ // Initializes DecryptingDemuxerStreams if audio/video stream is encrypted.
+ void InitAudioDecryptingDemuxerStream();
+ void InitVideoDecryptingDemuxerStream();
+
+ // Callbacks for DecryptingDemuxerStream::Initialize().
+ void OnAudioDecryptingDemuxerStreamInitDone(media::PipelineStatus status);
+ void OnVideoDecryptingDemuxerStreamInitDone(media::PipelineStatus status);
+
+ // Callback for Demuxer seek. It will call ResetAudioDecryptingDemuxerStream()
+ // as part of the reset callback chain.
void OnDemuxerSeekDone(unsigned seek_request_id,
media::PipelineStatus status);
+
+ // Resets AudioDecryptingDemuxerStream if it exists. Then it will call
+ // ResetVideoDecryptingDemuxerStream() as part of the reset callback chain.
+ void ResetAudioDecryptingDemuxerStream();
+
+ // Resets VideoDecryptingDemuxerStream if it exists. Then it will call
+ // SendSeekRequestAck() as part of the reset callback chain.
+ void ResetVideoDecryptingDemuxerStream();
+
+ // Sends SeekRequestAck to the browser.
+ void SendSeekRequestAck();
+
void OnDemuxerStopDone();
void OnDemuxerOpened();
void OnNeedKey(const std::string& type,
@@ -108,17 +136,17 @@ class MediaSourceDelegate : public media::DemuxerHost {
scoped_ptr<media::TextTrack> OnAddTextTrack(media::TextKind kind,
const std::string& label,
const std::string& language);
- void NotifyDemuxerReady(const std::string& key_system);
+ void NotifyDemuxerReady();
bool CanNotifyDemuxerReady();
// Reads an access unit from the demuxer stream |stream| and stores it in
// the |index|th access unit in |params|.
void ReadFromDemuxerStream(
- media::DemuxerStream* stream,
+ media::DemuxerStream::Type type,
media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
size_t index);
void OnBufferReady(
- media::DemuxerStream* stream,
+ media::DemuxerStream::Type type,
media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
size_t index,
media::DemuxerStream::Status status,
@@ -127,6 +155,8 @@ class MediaSourceDelegate : public media::DemuxerHost {
// Helper function for calculating duration.
int GetDurationMs();
+ bool HasEncryptedStream();
+
base::WeakPtrFactory<MediaSourceDelegate> weak_this_;
WebMediaPlayerProxyAndroid* proxy_;
@@ -139,6 +169,15 @@ class MediaSourceDelegate : public media::DemuxerHost {
scoped_ptr<media::ChunkDemuxer> chunk_demuxer_;
scoped_ptr<WebKit::WebMediaSource> media_source_;
media::Demuxer* demuxer_;
+ bool is_demuxer_ready_;
+
+ media::SetDecryptorReadyCB set_decryptor_ready_cb_;
+
+ scoped_ptr<media::DecryptingDemuxerStream> audio_decrypting_demuxer_stream_;
+ scoped_ptr<media::DecryptingDemuxerStream> video_decrypting_demuxer_stream_;
+
+ media::DemuxerStream* audio_stream_;
+ media::DemuxerStream* video_stream_;
media::PipelineStatistics statistics_;
media::Ranges<base::TimeDelta> buffered_time_ranges_;
@@ -155,14 +194,16 @@ class MediaSourceDelegate : public media::DemuxerHost {
// through GenerateKeyRequest() directly from WebKit.
std::string init_data_type_;
- scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> audio_params_;
- scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> video_params_;
+ media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params audio_params_;
+ media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params video_params_;
bool seeking_;
base::TimeDelta last_seek_time_;
unsigned last_seek_request_id_;
bool key_added_;
+ std::string key_system_;
+
size_t access_unit_size_;
DISALLOW_COPY_AND_ASSIGN(MediaSourceDelegate);
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 7096924..ce96b13 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -141,7 +141,6 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
}
if (WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
- // |decryptor_| is owned, so Unretained() is safe here.
decryptor_.reset(new ProxyDecryptor(
#if defined(ENABLE_PEPPER_CDMS)
client,
@@ -151,6 +150,7 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
// WebMediaPlayer.
scoped_ptr<media::MediaKeys>(new ProxyMediaKeys(proxy_, player_id_)),
#endif // defined(ENABLE_PEPPER_CDMS)
+ // |decryptor_| is owned, so Unretained() is safe here.
base::Bind(&WebMediaPlayerAndroid::OnKeyAdded, base::Unretained(this)),
base::Bind(&WebMediaPlayerAndroid::OnKeyError, base::Unretained(this)),
base::Bind(&WebMediaPlayerAndroid::OnKeyMessage,
@@ -216,6 +216,12 @@ void WebMediaPlayerAndroid::load(const WebURL& url,
}
#endif
+ media::SetDecryptorReadyCB set_decryptor_ready_cb;
+ if (decryptor_) { // |decryptor_| can be NULL is EME if not enabled.
+ set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
+ base::Unretained(decryptor_.get()));
+ }
+
if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_URL) {
has_media_info_ = true;
media_source_delegate_.reset(
@@ -225,11 +231,14 @@ void WebMediaPlayerAndroid::load(const WebURL& url,
media_source_delegate_->InitializeMediaSource(
media_source,
base::Bind(&WebMediaPlayerAndroid::OnNeedKey, base::Unretained(this)),
+ set_decryptor_ready_cb,
base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
base::Unretained(this)),
BIND_TO_RENDER_LOOP(&WebMediaPlayerAndroid::OnDurationChange));
}
#if defined(GOOGLE_TV)
+ // TODO(xhwang): Pass set_decryptor_ready_cb in InitializeMediaStream() to
+ // enable ClearKey support for Google TV.
if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_STREAM) {
media_source_delegate_->InitializeMediaStream(
demuxer_,