diff options
Diffstat (limited to 'content/renderer')
-rw-r--r-- | content/renderer/BUILD.gn | 1 | ||||
-rw-r--r-- | content/renderer/media/android/webmediaplayer_android.cc | 2 | ||||
-rw-r--r-- | content/renderer/media/android/webmediaplayer_android.h | 4 | ||||
-rw-r--r-- | content/renderer/media/crypto/encrypted_media_player_support_impl.cc | 475 | ||||
-rw-r--r-- | content/renderer/media/crypto/encrypted_media_player_support_impl.h | 131 | ||||
-rw-r--r-- | content/renderer/media/crypto/proxy_decryptor.cc | 312 | ||||
-rw-r--r-- | content/renderer/media/crypto/proxy_decryptor.h | 131 | ||||
-rw-r--r-- | content/renderer/render_frame_impl.cc | 13 |
8 files changed, 13 insertions, 1056 deletions
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 22acf49b..bfe9605 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn @@ -83,7 +83,6 @@ source_set("renderer") { if (is_android) { sources -= [ "media/audio_decoder.cc", - "media/crypto/encrypted_media_player_support_impl.cc", ] sources += [ "external_popup_menu.cc", diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 196b9a7..deb3417 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc @@ -1508,7 +1508,7 @@ WebMediaPlayerAndroid::GenerateKeyRequestInternal( // We do not support run-time switching between key systems for now. if (current_key_system_.empty()) { if (!proxy_decryptor_) { - proxy_decryptor_.reset(new ProxyDecryptor( + proxy_decryptor_.reset(new media::ProxyDecryptor( base::Bind(&WebMediaPlayerAndroid::OnKeyAdded, weak_factory_.GetWeakPtr()), base::Bind(&WebMediaPlayerAndroid::OnKeyError, diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 771074d..0da37eb 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h @@ -22,12 +22,12 @@ #include "content/renderer/media/android/media_info_loader.h" #include "content/renderer/media/android/media_source_delegate.h" #include "content/renderer/media/android/stream_texture_factory.h" -#include "content/renderer/media/crypto/proxy_decryptor.h" #include "gpu/command_buffer/common/mailbox.h" #include "media/base/android/media_player_android.h" #include "media/base/demuxer_stream.h" #include "media/base/media_keys.h" #include "media/base/time_delta_interpolator.h" +#include "media/cdm/proxy_decryptor.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/WebKit/public/platform/WebMediaPlayer.h" #include "third_party/WebKit/public/platform/WebSize.h" @@ -473,7 +473,7 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer, std::string init_data_type_; // Manages decryption keys and decrypts encrypted frames. - scoped_ptr<ProxyDecryptor> proxy_decryptor_; + scoped_ptr<media::ProxyDecryptor> proxy_decryptor_; // Non-owned pointer to the CDM. Updated via calls to // setContentDecryptionModule(). diff --git a/content/renderer/media/crypto/encrypted_media_player_support_impl.cc b/content/renderer/media/crypto/encrypted_media_player_support_impl.cc deleted file mode 100644 index 86e3329..0000000 --- a/content/renderer/media/crypto/encrypted_media_player_support_impl.cc +++ /dev/null @@ -1,475 +0,0 @@ -// Copyright 2014 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 "content/renderer/media/crypto/encrypted_media_player_support_impl.h" - -#include <string> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/metrics/histogram.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "content/renderer/media/crypto/render_cdm_factory.h" -#include "media/base/bind_to_current_loop.h" -#include "media/base/key_systems.h" -#include "media/blink/encrypted_media_player_support.h" -#include "media/blink/webcontentdecryptionmodule_impl.h" -#include "third_party/WebKit/public/platform/WebContentDecryptionModule.h" -#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h" -#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" - -#if defined(ENABLE_PEPPER_CDMS) -#include "content/renderer/media/crypto/pepper_cdm_wrapper_impl.h" -#elif defined(ENABLE_BROWSER_CDMS) -#error Browser side CDM in WMPI for prefixed EME API not supported yet. -#endif - -using blink::WebMediaPlayer; -using blink::WebMediaPlayerClient; -using blink::WebString; - -namespace content { - -#define BIND_TO_RENDER_LOOP(function) \ - (media::BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) - -#define BIND_TO_RENDER_LOOP1(function, arg1) \ - (media::BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1))) - -// Prefix for histograms related to Encrypted Media Extensions. -static const char* kMediaEme = "Media.EME."; - -// Used for calls to decryptor_ready_cb where the result can be ignored. -static void DoNothing(bool success) { -} - -// Convert a WebString to ASCII, falling back on an empty string in the case -// of a non-ASCII string. -static std::string ToASCIIOrEmpty(const WebString& string) { - return base::IsStringASCII(string) ? base::UTF16ToASCII(string) - : std::string(); -} - -// Helper functions to report media EME related stats to UMA. They follow the -// convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and -// UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is -// that UMA_* macros require the names to be constant throughout the process' -// lifetime. -static void EmeUMAHistogramEnumeration(const std::string& key_system, - const std::string& method, - int sample, - int boundary_value) { - base::LinearHistogram::FactoryGet( - kMediaEme + media::GetKeySystemNameForUMA(key_system) + "." + method, - 1, boundary_value, boundary_value + 1, - base::Histogram::kUmaTargetedHistogramFlag)->Add(sample); -} - -static void EmeUMAHistogramCounts(const std::string& key_system, - const std::string& method, - int sample) { - // Use the same parameters as UMA_HISTOGRAM_COUNTS. - base::Histogram::FactoryGet( - kMediaEme + media::GetKeySystemNameForUMA(key_system) + "." + method, - 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample); -} - -// Helper enum for reporting generateKeyRequest/addKey histograms. -enum MediaKeyException { - kUnknownResultId, - kSuccess, - kKeySystemNotSupported, - kInvalidPlayerState, - kMaxMediaKeyException -}; - -static MediaKeyException MediaKeyExceptionForUMA( - WebMediaPlayer::MediaKeyException e) { - switch (e) { - case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported: - return kKeySystemNotSupported; - case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState: - return kInvalidPlayerState; - case WebMediaPlayer::MediaKeyExceptionNoError: - return kSuccess; - default: - return kUnknownResultId; - } -} - -// Helper for converting |key_system| name and exception |e| to a pair of enum -// values from above, for reporting to UMA. -static void ReportMediaKeyExceptionToUMA(const std::string& method, - const std::string& key_system, - WebMediaPlayer::MediaKeyException e) { - MediaKeyException result_id = MediaKeyExceptionForUMA(e); - DCHECK_NE(result_id, kUnknownResultId) << e; - EmeUMAHistogramEnumeration( - key_system, method, result_id, kMaxMediaKeyException); -} - -// Guess the type of |init_data|. This is only used to handle some corner cases -// so we keep it as simple as possible without breaking major use cases. -static std::string GuessInitDataType(const unsigned char* init_data, - unsigned init_data_length) { - // Most WebM files use KeyId of 16 bytes. CENC init data is always >16 bytes. - if (init_data_length == 16) - return "webm"; - - return "cenc"; -} - -scoped_ptr<media::EncryptedMediaPlayerSupport> -EncryptedMediaPlayerSupportImpl::Create(blink::WebMediaPlayerClient* client) { - return scoped_ptr<EncryptedMediaPlayerSupport>( - new EncryptedMediaPlayerSupportImpl(client)); -} - -EncryptedMediaPlayerSupportImpl::EncryptedMediaPlayerSupportImpl( - blink::WebMediaPlayerClient* client) - : client_(client), - web_cdm_(NULL) { -} - -EncryptedMediaPlayerSupportImpl::~EncryptedMediaPlayerSupportImpl() { -} - -WebMediaPlayer::MediaKeyException -EncryptedMediaPlayerSupportImpl::GenerateKeyRequest( - blink::WebLocalFrame* frame, - const WebString& key_system, - const unsigned char* init_data, - unsigned init_data_length) { - DVLOG(1) << "generateKeyRequest: " << base::string16(key_system) << ": " - << std::string(reinterpret_cast<const char*>(init_data), - static_cast<size_t>(init_data_length)); - - std::string ascii_key_system = - media::GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system)); - - WebMediaPlayer::MediaKeyException e = - GenerateKeyRequestInternal(frame, ascii_key_system, init_data, - init_data_length); - ReportMediaKeyExceptionToUMA("generateKeyRequest", ascii_key_system, e); - return e; -} - -WebMediaPlayer::MediaKeyException -EncryptedMediaPlayerSupportImpl::GenerateKeyRequestInternal( - blink::WebLocalFrame* frame, - const std::string& key_system, - const unsigned char* init_data, - unsigned init_data_length) { - if (!media::IsConcreteSupportedKeySystem(key_system)) - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - - // We do not support run-time switching between key systems for now. - if (current_key_system_.empty()) { - if (!proxy_decryptor_) { - proxy_decryptor_.reset(new ProxyDecryptor( - BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnKeyAdded), - BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnKeyError), - BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnKeyMessage))); - } - - GURL security_origin(frame->document().securityOrigin().toString()); - -#if defined(ENABLE_PEPPER_CDMS) - RenderCdmFactory cdm_factory( - base::Bind(&PepperCdmWrapperImpl::Create, frame)); -#else - RenderCdmFactory cdm_factory; -#endif - - if (!proxy_decryptor_->InitializeCDM(&cdm_factory, key_system, - security_origin)) { - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - } - - if (proxy_decryptor_ && !decryptor_ready_cb_.is_null()) { - base::ResetAndReturn(&decryptor_ready_cb_) - .Run(proxy_decryptor_->GetDecryptor(), base::Bind(DoNothing)); - } - - current_key_system_ = key_system; - } else if (key_system != current_key_system_) { - return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; - } - - std::string init_data_type = init_data_type_; - if (init_data_type.empty()) - init_data_type = GuessInitDataType(init_data, init_data_length); - - // TODO(xhwang): We assume all streams are from the same container (thus have - // the same "type") for now. In the future, the "type" should be passed down - // from the application. - if (!proxy_decryptor_->GenerateKeyRequest( - init_data_type, init_data, init_data_length)) { - current_key_system_.clear(); - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - } - - return WebMediaPlayer::MediaKeyExceptionNoError; -} - -WebMediaPlayer::MediaKeyException EncryptedMediaPlayerSupportImpl::AddKey( - const WebString& key_system, - const unsigned char* key, - unsigned key_length, - const unsigned char* init_data, - unsigned init_data_length, - const WebString& session_id) { - DVLOG(1) << "addKey: " << base::string16(key_system) << ": " - << std::string(reinterpret_cast<const char*>(key), - static_cast<size_t>(key_length)) << ", " - << std::string(reinterpret_cast<const char*>(init_data), - static_cast<size_t>(init_data_length)) << " [" - << base::string16(session_id) << "]"; - - std::string ascii_key_system = - media::GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system)); - std::string ascii_session_id = ToASCIIOrEmpty(session_id); - - WebMediaPlayer::MediaKeyException e = AddKeyInternal(ascii_key_system, - key, - key_length, - init_data, - init_data_length, - ascii_session_id); - ReportMediaKeyExceptionToUMA("addKey", ascii_key_system, e); - return e; -} - -WebMediaPlayer::MediaKeyException -EncryptedMediaPlayerSupportImpl::AddKeyInternal( - const std::string& key_system, - const unsigned char* key, - unsigned key_length, - const unsigned char* init_data, - unsigned init_data_length, - const std::string& session_id) { - DCHECK(key); - DCHECK_GT(key_length, 0u); - - if (!media::IsConcreteSupportedKeySystem(key_system)) - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - - if (current_key_system_.empty() || key_system != current_key_system_) - return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; - - proxy_decryptor_->AddKey( - key, key_length, init_data, init_data_length, session_id); - return WebMediaPlayer::MediaKeyExceptionNoError; -} - -WebMediaPlayer::MediaKeyException -EncryptedMediaPlayerSupportImpl::CancelKeyRequest( - const WebString& key_system, - const WebString& session_id) { - DVLOG(1) << "cancelKeyRequest: " << base::string16(key_system) << ": " - << " [" << base::string16(session_id) << "]"; - - std::string ascii_key_system = - media::GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system)); - std::string ascii_session_id = ToASCIIOrEmpty(session_id); - - WebMediaPlayer::MediaKeyException e = - CancelKeyRequestInternal(ascii_key_system, ascii_session_id); - ReportMediaKeyExceptionToUMA("cancelKeyRequest", ascii_key_system, e); - return e; -} - -WebMediaPlayer::MediaKeyException -EncryptedMediaPlayerSupportImpl::CancelKeyRequestInternal( - const std::string& key_system, - const std::string& session_id) { - if (!media::IsConcreteSupportedKeySystem(key_system)) - return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; - - if (current_key_system_.empty() || key_system != current_key_system_) - return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState; - - proxy_decryptor_->CancelKeyRequest(session_id); - return WebMediaPlayer::MediaKeyExceptionNoError; -} - -void EncryptedMediaPlayerSupportImpl::SetInitialContentDecryptionModule( - blink::WebContentDecryptionModule* initial_cdm) { - // Used when loading media and no pipeline/decoder attached yet. - DCHECK(decryptor_ready_cb_.is_null()); - - web_cdm_ = media::ToWebContentDecryptionModuleImpl(initial_cdm); -} - -void EncryptedMediaPlayerSupportImpl::SetContentDecryptionModule( - blink::WebContentDecryptionModule* cdm) { - // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324 - if (!cdm) - return; - - web_cdm_ = media::ToWebContentDecryptionModuleImpl(cdm); - - if (web_cdm_ && !decryptor_ready_cb_.is_null()) - base::ResetAndReturn(&decryptor_ready_cb_) - .Run(web_cdm_->GetDecryptor(), base::Bind(DoNothing)); -} - -void EncryptedMediaPlayerSupportImpl::SetContentDecryptionModule( - blink::WebContentDecryptionModule* cdm, - blink::WebContentDecryptionModuleResult result) { - // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324 - if (!cdm) { - result.completeWithError( - blink::WebContentDecryptionModuleExceptionNotSupportedError, - 0, - "Null MediaKeys object is not supported."); - return; - } - - web_cdm_ = media::ToWebContentDecryptionModuleImpl(cdm); - - if (web_cdm_ && !decryptor_ready_cb_.is_null()) { - base::ResetAndReturn(&decryptor_ready_cb_) - .Run(web_cdm_->GetDecryptor(), BIND_TO_RENDER_LOOP1( - &EncryptedMediaPlayerSupportImpl::ContentDecryptionModuleAttached, - result)); - } else { - // No pipeline/decoder connected, so resolve the promise. When something - // is connected, setting the CDM will happen in SetDecryptorReadyCB(). - ContentDecryptionModuleAttached(result, true); - } -} - -void EncryptedMediaPlayerSupportImpl::ContentDecryptionModuleAttached( - blink::WebContentDecryptionModuleResult result, - bool success) { - if (success) { - result.complete(); - return; - } - - result.completeWithError( - blink::WebContentDecryptionModuleExceptionNotSupportedError, - 0, - "Unable to set MediaKeys object"); -} - -media::SetDecryptorReadyCB -EncryptedMediaPlayerSupportImpl::CreateSetDecryptorReadyCB() { - return BIND_TO_RENDER_LOOP( - &EncryptedMediaPlayerSupportImpl::SetDecryptorReadyCB); -} - -media::Demuxer::NeedKeyCB -EncryptedMediaPlayerSupportImpl::CreateNeedKeyCB() { - return BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupportImpl::OnNeedKey); -} - -void EncryptedMediaPlayerSupportImpl::OnPipelineDecryptError() { - EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1); -} - -void EncryptedMediaPlayerSupportImpl::OnNeedKey(const std::string& type, - const std::vector<uint8>& init_data) { - // Do not fire NeedKey event if encrypted media is not enabled. - if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() && - !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) { - return; - } - - UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1); - - DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_); - if (init_data_type_.empty()) - init_data_type_ = type; - - const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0]; - client_->encrypted( - WebString::fromUTF8(type), init_data_ptr, init_data.size()); -} - -void EncryptedMediaPlayerSupportImpl::OnKeyAdded( - const std::string& session_id) { - EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1); - client_->keyAdded( - WebString::fromUTF8(media::GetPrefixedKeySystemName(current_key_system_)), - WebString::fromUTF8(session_id)); -} - -void EncryptedMediaPlayerSupportImpl::OnKeyError(const std::string& session_id, - media::MediaKeys::KeyError error_code, - uint32 system_code) { - EmeUMAHistogramEnumeration(current_key_system_, "KeyError", - error_code, media::MediaKeys::kMaxKeyError); - - uint16 short_system_code = 0; - if (system_code > std::numeric_limits<uint16>::max()) { - LOG(WARNING) << "system_code exceeds unsigned short limit."; - short_system_code = std::numeric_limits<uint16>::max(); - } else { - short_system_code = static_cast<uint16>(system_code); - } - - client_->keyError( - WebString::fromUTF8(media::GetPrefixedKeySystemName(current_key_system_)), - WebString::fromUTF8(session_id), - static_cast<WebMediaPlayerClient::MediaKeyErrorCode>(error_code), - short_system_code); -} - -void EncryptedMediaPlayerSupportImpl::OnKeyMessage( - const std::string& session_id, - const std::vector<uint8>& message, - const GURL& destination_url) { - DCHECK(destination_url.is_empty() || destination_url.is_valid()); - - client_->keyMessage( - WebString::fromUTF8(media::GetPrefixedKeySystemName(current_key_system_)), - WebString::fromUTF8(session_id), - message.empty() ? NULL : &message[0], - message.size(), - destination_url); -} - -void EncryptedMediaPlayerSupportImpl::SetDecryptorReadyCB( - const media::DecryptorReadyCB& decryptor_ready_cb) { - // Cancels the previous decryptor request. - if (decryptor_ready_cb.is_null()) { - if (!decryptor_ready_cb_.is_null()) { - base::ResetAndReturn(&decryptor_ready_cb_) - .Run(NULL, base::Bind(DoNothing)); - } - return; - } - - // TODO(xhwang): Support multiple decryptor notification request (e.g. from - // video and audio). The current implementation is okay for the current - // media pipeline since we initialize audio and video decoders in sequence. - // But WebMediaPlayerImpl should not depend on media pipeline's implementation - // detail. - DCHECK(decryptor_ready_cb_.is_null()); - - // Mixed use of prefixed and unprefixed EME APIs is disallowed by Blink. - DCHECK(!proxy_decryptor_ || !web_cdm_); - - if (proxy_decryptor_) { - decryptor_ready_cb.Run(proxy_decryptor_->GetDecryptor(), - base::Bind(DoNothing)); - return; - } - - if (web_cdm_) { - decryptor_ready_cb.Run(web_cdm_->GetDecryptor(), base::Bind(DoNothing)); - return; - } - - decryptor_ready_cb_ = decryptor_ready_cb; -} - -} // namespace content diff --git a/content/renderer/media/crypto/encrypted_media_player_support_impl.h b/content/renderer/media/crypto/encrypted_media_player_support_impl.h deleted file mode 100644 index 88d55d1..0000000 --- a/content/renderer/media/crypto/encrypted_media_player_support_impl.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2014 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 CONTENT_RENDERER_MEDIA_CRYPTO_ENCRYPTED_MEDIA_PLAYER_SUPPORT_IMPL_H_ -#define CONTENT_RENDERER_MEDIA_CRYPTO_ENCRYPTED_MEDIA_PLAYER_SUPPORT_IMPL_H_ - -#include <string> -#include <vector> - -#include "base/memory/weak_ptr.h" -#include "content/renderer/media/crypto/proxy_decryptor.h" -#include "media/blink/encrypted_media_player_support.h" -#include "media/blink/webcontentdecryptionmodule_impl.h" - -namespace blink { -class WebMediaPlayerClient; -} - -namespace content { - -class WebContentDecryptionModuleImpl; - -class EncryptedMediaPlayerSupportImpl - : public media::EncryptedMediaPlayerSupport, - public base::SupportsWeakPtr<EncryptedMediaPlayerSupportImpl> { - public: - static scoped_ptr<EncryptedMediaPlayerSupport> Create( - blink::WebMediaPlayerClient* client); - - ~EncryptedMediaPlayerSupportImpl() override; - - // EncryptedMediaPlayerSupport implementation. - blink::WebMediaPlayer::MediaKeyException GenerateKeyRequest( - blink::WebLocalFrame* frame, - const blink::WebString& key_system, - const unsigned char* init_data, - unsigned init_data_length) override; - - blink::WebMediaPlayer::MediaKeyException AddKey( - const blink::WebString& key_system, - const unsigned char* key, - unsigned key_length, - const unsigned char* init_data, - unsigned init_data_length, - const blink::WebString& session_id) override; - - blink::WebMediaPlayer::MediaKeyException CancelKeyRequest( - const blink::WebString& key_system, - const blink::WebString& session_id) override; - - void SetInitialContentDecryptionModule( - blink::WebContentDecryptionModule* initial_cdm) override; - - void SetContentDecryptionModule( - blink::WebContentDecryptionModule* cdm) override; - void SetContentDecryptionModule( - blink::WebContentDecryptionModule* cdm, - blink::WebContentDecryptionModuleResult result) override; - - media::SetDecryptorReadyCB CreateSetDecryptorReadyCB() override; - media::Demuxer::NeedKeyCB CreateNeedKeyCB() override; - - void OnPipelineDecryptError() override; - - private: - explicit EncryptedMediaPlayerSupportImpl(blink::WebMediaPlayerClient* client); - - // Requests that this object notifies when a decryptor is ready through the - // |decryptor_ready_cb| provided. - // If |decryptor_ready_cb| is null, the existing callback will be fired with - // NULL immediately and reset. - void SetDecryptorReadyCB(const media::DecryptorReadyCB& decryptor_ready_cb); - - blink::WebMediaPlayer::MediaKeyException GenerateKeyRequestInternal( - blink::WebLocalFrame* frame, - const std::string& key_system, - const unsigned char* init_data, - unsigned init_data_length); - - blink::WebMediaPlayer::MediaKeyException AddKeyInternal( - const std::string& key_system, - const unsigned char* key, - unsigned key_length, - const unsigned char* init_data, - unsigned init_data_length, - const std::string& session_id); - - blink::WebMediaPlayer::MediaKeyException CancelKeyRequestInternal( - const std::string& key_system, - const std::string& session_id); - - void OnNeedKey(const std::string& type, - const std::vector<uint8>& init_data); - - void OnKeyAdded(const std::string& session_id); - void OnKeyError(const std::string& session_id, - media::MediaKeys::KeyError error_code, - uint32 system_code); - void OnKeyMessage(const std::string& session_id, - const std::vector<uint8>& message, - const GURL& destination_url); - - void ContentDecryptionModuleAttached( - blink::WebContentDecryptionModuleResult result, - bool success); - - blink::WebMediaPlayerClient* client_; - - // The currently selected key system. Empty string means that no key system - // has been selected. - std::string current_key_system_; - - // Temporary for EME v0.1. In the future the init data type should be passed - // through GenerateKeyRequest() directly from WebKit. - std::string init_data_type_; - - // Manages decryption keys and decrypts encrypted frames. - scoped_ptr<ProxyDecryptor> proxy_decryptor_; - - // Non-owned pointer to the CDM. Updated via calls to - // setContentDecryptionModule(). - media::WebContentDecryptionModuleImpl* web_cdm_; - - media::DecryptorReadyCB decryptor_ready_cb_; - - DISALLOW_COPY_AND_ASSIGN(EncryptedMediaPlayerSupportImpl); -}; -} - -#endif // CONTENT_RENDERER_MEDIA_CRYPTO_ENCRYPTED_MEDIA_PLAYER_SUPPORT_IMPL_H_ diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc deleted file mode 100644 index 44a30fd..0000000 --- a/content/renderer/media/crypto/proxy_decryptor.cc +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 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 "content/renderer/media/crypto/proxy_decryptor.h" - -#include <cstring> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "media/base/cdm_callback_promise.h" -#include "media/base/cdm_factory.h" -#include "media/cdm/json_web_key.h" -#include "media/cdm/key_system_names.h" - -namespace content { - -// Special system code to signal a closed persistent session in a SessionError() -// call. This is needed because there is no SessionClosed() call in the prefixed -// EME API. -const int kSessionClosedSystemCode = 29127; - -ProxyDecryptor::ProxyDecryptor(const KeyAddedCB& key_added_cb, - const KeyErrorCB& key_error_cb, - const KeyMessageCB& key_message_cb) - : key_added_cb_(key_added_cb), - key_error_cb_(key_error_cb), - key_message_cb_(key_message_cb), - is_clear_key_(false), - weak_ptr_factory_(this) { - DCHECK(!key_added_cb_.is_null()); - DCHECK(!key_error_cb_.is_null()); - DCHECK(!key_message_cb_.is_null()); -} - -ProxyDecryptor::~ProxyDecryptor() { - // Destroy the decryptor explicitly before destroying the plugin. - media_keys_.reset(); -} - -media::Decryptor* ProxyDecryptor::GetDecryptor() { - return media_keys_ ? media_keys_->GetDecryptor() : NULL; -} - -#if defined(ENABLE_BROWSER_CDMS) -int ProxyDecryptor::GetCdmId() { - return media_keys_->GetCdmId(); -} -#endif - -bool ProxyDecryptor::InitializeCDM(media::CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin) { - DVLOG(1) << "InitializeCDM: key_system = " << key_system; - - DCHECK(!media_keys_); - media_keys_ = CreateMediaKeys(cdm_factory, key_system, security_origin); - if (!media_keys_) - return false; - - is_clear_key_ = - media::IsClearKey(key_system) || media::IsExternalClearKey(key_system); - return true; -} - -// Returns true if |data| is prefixed with |header| and has data after the -// |header|. -bool HasHeader(const uint8* data, int data_length, const std::string& header) { - return static_cast<size_t>(data_length) > header.size() && - std::equal(data, data + header.size(), header.begin()); -} - -// Removes the first |length| items from |data|. -void StripHeader(std::vector<uint8>& data, size_t length) { - data.erase(data.begin(), data.begin() + length); -} - -bool ProxyDecryptor::GenerateKeyRequest(const std::string& init_data_type, - const uint8* init_data, - int init_data_length) { - DVLOG(1) << "GenerateKeyRequest()"; - const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; - const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; - - SessionCreationType session_creation_type = TemporarySession; - std::vector<uint8> init_data_vector(init_data, init_data + init_data_length); - if (HasHeader(init_data, init_data_length, kPrefixedApiLoadSessionHeader)) { - session_creation_type = LoadSession; - StripHeader(init_data_vector, strlen(kPrefixedApiLoadSessionHeader)); - } else if (HasHeader(init_data, - init_data_length, - kPrefixedApiPersistentSessionHeader)) { - session_creation_type = PersistentSession; - StripHeader(init_data_vector, strlen(kPrefixedApiPersistentSessionHeader)); - } - - scoped_ptr<media::NewSessionCdmPromise> promise( - new media::CdmCallbackPromise<std::string>( - base::Bind(&ProxyDecryptor::SetSessionId, - weak_ptr_factory_.GetWeakPtr(), - session_creation_type), - base::Bind(&ProxyDecryptor::OnSessionError, - weak_ptr_factory_.GetWeakPtr(), - std::string()))); // No session id until created. - uint8* init_data_vector_data = - (init_data_vector.size() > 0) ? &init_data_vector[0] : nullptr; - - if (session_creation_type == LoadSession) { - media_keys_->LoadSession( - std::string(reinterpret_cast<const char*>(init_data_vector_data), - init_data_vector.size()), - promise.Pass()); - return true; - } - - media::MediaKeys::SessionType session_type = - session_creation_type == PersistentSession - ? media::MediaKeys::PERSISTENT_SESSION - : media::MediaKeys::TEMPORARY_SESSION; - - media_keys_->CreateSession(init_data_type, - init_data_vector_data, - init_data_vector.size(), - session_type, - promise.Pass()); - return true; -} - -void ProxyDecryptor::AddKey(const uint8* key, - int key_length, - const uint8* init_data, - int init_data_length, - const std::string& web_session_id) { - DVLOG(1) << "AddKey()"; - - // In the prefixed API, the session parameter provided to addKey() is - // optional, so use the single existing session if it exists. - // TODO(jrummell): remove when the prefixed API is removed. - std::string session_id(web_session_id); - if (session_id.empty()) { - if (active_sessions_.size() == 1) { - base::hash_map<std::string, bool>::iterator it = active_sessions_.begin(); - session_id = it->first; - } else { - OnSessionError(std::string(), - media::MediaKeys::NOT_SUPPORTED_ERROR, - 0, - "SessionId not specified."); - return; - } - } - - scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( - base::Bind(&ProxyDecryptor::OnSessionReady, - weak_ptr_factory_.GetWeakPtr(), - web_session_id), - base::Bind(&ProxyDecryptor::OnSessionError, - weak_ptr_factory_.GetWeakPtr(), - web_session_id))); - - // EME WD spec only supports a single array passed to the CDM. For - // Clear Key using v0.1b, both arrays are used (|init_data| is key_id). - // Since the EME WD spec supports the key as a JSON Web Key, - // convert the 2 arrays to a JWK and pass it as the single array. - if (is_clear_key_) { - // Decryptor doesn't support empty key ID (see http://crbug.com/123265). - // So ensure a non-empty value is passed. - if (!init_data) { - static const uint8 kDummyInitData[1] = {0}; - init_data = kDummyInitData; - init_data_length = arraysize(kDummyInitData); - } - - std::string jwk = - media::GenerateJWKSet(key, key_length, init_data, init_data_length); - DCHECK(!jwk.empty()); - media_keys_->UpdateSession(session_id, - reinterpret_cast<const uint8*>(jwk.data()), - jwk.size(), - promise.Pass()); - return; - } - - media_keys_->UpdateSession(session_id, key, key_length, promise.Pass()); -} - -void ProxyDecryptor::CancelKeyRequest(const std::string& web_session_id) { - DVLOG(1) << "CancelKeyRequest()"; - - scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( - base::Bind(&ProxyDecryptor::OnSessionClosed, - weak_ptr_factory_.GetWeakPtr(), - web_session_id), - base::Bind(&ProxyDecryptor::OnSessionError, - weak_ptr_factory_.GetWeakPtr(), - web_session_id))); - media_keys_->RemoveSession(web_session_id, promise.Pass()); -} - -scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys( - media::CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin) { - base::WeakPtr<ProxyDecryptor> weak_this = weak_ptr_factory_.GetWeakPtr(); - return cdm_factory->Create( - key_system, - security_origin, - base::Bind(&ProxyDecryptor::OnSessionMessage, weak_this), - base::Bind(&ProxyDecryptor::OnSessionReady, weak_this), - base::Bind(&ProxyDecryptor::OnSessionClosed, weak_this), - base::Bind(&ProxyDecryptor::OnSessionError, weak_this), - base::Bind(&ProxyDecryptor::OnSessionKeysChange, weak_this), - base::Bind(&ProxyDecryptor::OnSessionExpirationUpdate, weak_this)); -} - -void ProxyDecryptor::OnSessionMessage(const std::string& web_session_id, - const std::vector<uint8>& message, - const GURL& destination_url) { - // Assumes that OnSessionCreated() has been called before this. - - // For ClearKey, convert the message from JSON into just passing the key - // as the message. If unable to extract the key, return the message unchanged. - if (is_clear_key_) { - std::vector<uint8> key; - if (media::ExtractFirstKeyIdFromLicenseRequest(message, &key)) { - key_message_cb_.Run(web_session_id, key, destination_url); - return; - } - } - - key_message_cb_.Run(web_session_id, message, destination_url); -} - -void ProxyDecryptor::OnSessionKeysChange(const std::string& web_session_id, - bool has_additional_usable_key) { - // EME v0.1b doesn't support this event. -} - -void ProxyDecryptor::OnSessionExpirationUpdate( - const std::string& web_session_id, - const base::Time& new_expiry_time) { - // EME v0.1b doesn't support this event. -} - -void ProxyDecryptor::OnSessionReady(const std::string& web_session_id) { - key_added_cb_.Run(web_session_id); -} - -void ProxyDecryptor::OnSessionClosed(const std::string& web_session_id) { - base::hash_map<std::string, bool>::iterator it = - active_sessions_.find(web_session_id); - - // Latest EME spec separates closing a session ("allows an application to - // indicate that it no longer needs the session") and actually closing the - // session (done by the CDM at any point "such as in response to a close() - // call, when the session is no longer needed, or when system resources are - // lost.") Thus the CDM may cause 2 close() events -- one to resolve the - // close() promise, and a second to actually close the session. Prefixed EME - // only expects 1 close event, so drop the second (and subsequent) events. - // However, this means we can't tell if the CDM is generating spurious close() - // events. - if (it == active_sessions_.end()) - return; - - if (it->second) { - OnSessionError(web_session_id, - media::MediaKeys::NOT_SUPPORTED_ERROR, - kSessionClosedSystemCode, - "Do not close persistent sessions."); - } - active_sessions_.erase(it); -} - -void ProxyDecryptor::OnSessionError(const std::string& web_session_id, - media::MediaKeys::Exception exception_code, - uint32 system_code, - const std::string& error_message) { - // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed - // EME has different error message, so all the specific error events will - // get lost. - media::MediaKeys::KeyError error_code; - switch (exception_code) { - case media::MediaKeys::CLIENT_ERROR: - error_code = media::MediaKeys::kClientError; - break; - case media::MediaKeys::OUTPUT_ERROR: - error_code = media::MediaKeys::kOutputError; - break; - default: - // This will include all other CDM4 errors and any error generated - // by CDM5 or later. - error_code = media::MediaKeys::kUnknownError; - break; - } - key_error_cb_.Run(web_session_id, error_code, system_code); -} - -void ProxyDecryptor::SetSessionId(SessionCreationType session_type, - const std::string& web_session_id) { - // Loaded sessions are considered persistent. - bool is_persistent = - session_type == PersistentSession || session_type == LoadSession; - active_sessions_.insert(std::make_pair(web_session_id, is_persistent)); - - // For LoadSession(), generate the SessionReady event. - if (session_type == LoadSession) - OnSessionReady(web_session_id); -} - -} // namespace content diff --git a/content/renderer/media/crypto/proxy_decryptor.h b/content/renderer/media/crypto/proxy_decryptor.h deleted file mode 100644 index 62f2e8e..0000000 --- a/content/renderer/media/crypto/proxy_decryptor.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 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 CONTENT_RENDERER_MEDIA_CRYPTO_PROXY_DECRYPTOR_H_ -#define CONTENT_RENDERER_MEDIA_CRYPTO_PROXY_DECRYPTOR_H_ - -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "media/base/decryptor.h" -#include "media/base/media_keys.h" - -class GURL; - -namespace media { -class CdmFactory; -} - -namespace content { - -// ProxyDecryptor is for EME v0.1b only. It should not be used for the WD API. -// A decryptor proxy that creates a real decryptor object on demand and -// forwards decryptor calls to it. -// -// TODO(xhwang): Currently we don't support run-time switching among decryptor -// objects. Fix this when needed. -// TODO(xhwang): The ProxyDecryptor is not a Decryptor. Find a better name! -class ProxyDecryptor { - public: - // These are similar to the callbacks in media_keys.h, but pass back the - // web session ID rather than the internal session ID. - typedef base::Callback<void(const std::string& session_id)> KeyAddedCB; - typedef base::Callback<void(const std::string& session_id, - media::MediaKeys::KeyError error_code, - uint32 system_code)> KeyErrorCB; - typedef base::Callback<void(const std::string& session_id, - const std::vector<uint8>& message, - const GURL& destination_url)> KeyMessageCB; - - ProxyDecryptor(const KeyAddedCB& key_added_cb, - const KeyErrorCB& key_error_cb, - const KeyMessageCB& key_message_cb); - virtual ~ProxyDecryptor(); - - // Returns the Decryptor associated with this object. May be NULL if no - // Decryptor is associated. - media::Decryptor* GetDecryptor(); - -#if defined(ENABLE_BROWSER_CDMS) - // Returns the CDM ID associated with this object. May be kInvalidCdmId if no - // CDM ID is associated, such as when Clear Key is used. - int GetCdmId(); -#endif - - // Only call this once. - bool InitializeCDM(media::CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin); - - // May only be called after InitializeCDM() succeeds. - bool GenerateKeyRequest(const std::string& init_data_type, - const uint8* init_data, - int init_data_length); - void AddKey(const uint8* key, int key_length, - const uint8* init_data, int init_data_length, - const std::string& session_id); - void CancelKeyRequest(const std::string& session_id); - - private: - // Helper function to create MediaKeys to handle the given |key_system|. - scoped_ptr<media::MediaKeys> CreateMediaKeys( - media::CdmFactory* cdm_factory, - const std::string& key_system, - const GURL& security_origin); - - // Callbacks for firing session events. - void OnSessionMessage(const std::string& web_session_id, - const std::vector<uint8>& message, - const GURL& default_url); - void OnSessionKeysChange(const std::string& web_session_id, - bool has_additional_usable_key); - void OnSessionExpirationUpdate(const std::string& web_session_id, - const base::Time& new_expiry_time); - void OnSessionReady(const std::string& web_session_id); - void OnSessionClosed(const std::string& web_session_id); - void OnSessionError(const std::string& web_session_id, - media::MediaKeys::Exception exception_code, - uint32 system_code, - const std::string& error_message); - - enum SessionCreationType { - TemporarySession, - PersistentSession, - LoadSession - }; - - // Called when a session is actually created or loaded. - void SetSessionId(SessionCreationType session_type, - const std::string& web_session_id); - - // The real MediaKeys that manages key operations for the ProxyDecryptor. - scoped_ptr<media::MediaKeys> media_keys_; - - // Callbacks for firing key events. - KeyAddedCB key_added_cb_; - KeyErrorCB key_error_cb_; - KeyMessageCB key_message_cb_; - - // Keep track of both persistent and non-persistent sessions. - base::hash_map<std::string, bool> active_sessions_; - - bool is_clear_key_; - -#if defined(ENABLE_BROWSER_CDMS) - int cdm_id_; -#endif - - // NOTE: Weak pointers must be invalidated before all other member variables. - base::WeakPtrFactory<ProxyDecryptor> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ProxyDecryptor); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_CRYPTO_PROXY_DECRYPTOR_H_ diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 8e70202..8678b58 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -70,7 +70,6 @@ #include "content/renderer/internal_document_state_data.h" #include "content/renderer/manifest/manifest_manager.h" #include "content/renderer/media/audio_renderer_mixer_manager.h" -#include "content/renderer/media/crypto/encrypted_media_player_support_impl.h" #include "content/renderer/media/crypto/render_cdm_factory.h" #include "content/renderer/media/media_stream_dispatcher.h" #include "content/renderer/media/media_stream_renderer_factory.h" @@ -97,6 +96,7 @@ #include "gin/modules/module_registry.h" #include "media/base/audio_renderer_mixer_input.h" #include "media/base/renderer.h" +#include "media/blink/encrypted_media_player_support.h" #include "media/blink/webcontentdecryptionmodule_impl.h" #include "media/blink/webmediaplayer_impl.h" #include "media/blink/webmediaplayer_params.h" @@ -1773,15 +1773,22 @@ blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer( render_thread->GetGpuFactories(), render_thread->GetMediaThreadTaskRunner(), render_thread->compositor_message_loop_proxy(), - base::Bind(&EncryptedMediaPlayerSupportImpl::Create), initial_cdm); +#if defined(ENABLE_PEPPER_CDMS) + scoped_ptr<media::CdmFactory> cdm_factory( + new RenderCdmFactory(base::Bind(&PepperCdmWrapperImpl::Create, frame))); +#else + scoped_ptr<media::CdmFactory> cdm_factory(new RenderCdmFactory()); +#endif + scoped_ptr<media::Renderer> media_renderer = GetContentClient()->renderer()->CreateMediaRenderer( this, render_thread->GetMediaThreadTaskRunner()); return new media::WebMediaPlayerImpl( - frame, client, weak_factory_.GetWeakPtr(), media_renderer.Pass(), params); + frame, client, weak_factory_.GetWeakPtr(), media_renderer.Pass(), + cdm_factory.Pass(), params); #endif // defined(OS_ANDROID) } |