summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-03-18 08:12:19 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-03-18 08:12:19 +0100
commitc7c3c8600febd196152e5b23f687cbe8aa493627 (patch)
treea0a4cdee6d626fb3a983daf113f3b171c9143929
parentd791dfed61bbc963351e5965657a3b13d4e6dceb (diff)
parente9261d329b443e588de408ff85917ac29d4ab62d (diff)
downloadUXP-c7c3c8600febd196152e5b23f687cbe8aa493627.tar
UXP-c7c3c8600febd196152e5b23f687cbe8aa493627.tar.gz
UXP-c7c3c8600febd196152e5b23f687cbe8aa493627.tar.lz
UXP-c7c3c8600febd196152e5b23f687cbe8aa493627.tar.xz
UXP-c7c3c8600febd196152e5b23f687cbe8aa493627.zip
Merge branch 'cdm-work'
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineAdapter.cpp10
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp101
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineDecryptor.h24
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineUtils.cpp4
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineUtils.h10
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h2
-rw-r--r--dom/media/gmp/widevine-adapter/content_decryption_module.h289
-rw-r--r--dom/media/gmp/widevine-adapter/content_decryption_module_export.h22
-rw-r--r--dom/media/gmp/widevine-adapter/content_decryption_module_ext.h64
9 files changed, 353 insertions, 173 deletions
diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
index 74b5c38e8..57d4ecec2 100644
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -46,7 +46,7 @@ void* GetCdmHost(int aHostInterfaceVersion, void* aUserData)
Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData);
MOZ_ASSERT(decryptor);
- return static_cast<cdm::Host_8*>(decryptor);
+ return static_cast<cdm::Host_9*>(decryptor);
}
#define STRINGIFY(s) _STRINGIFY(s)
@@ -106,8 +106,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName,
WidevineDecryptor* decryptor = new WidevineDecryptor();
- auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
- create(cdm::ContentDecryptionModule::kVersion,
+ auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_9*>(
+ create(cdm::ContentDecryptionModule_9::kVersion,
kEMEKeySystemWidevine.get(),
kEMEKeySystemWidevine.Length(),
&GetCdmHost,
@@ -161,8 +161,8 @@ WidevineAdapter::Supports(int32_t aModuleVersion,
int32_t aHostVersion)
{
return aModuleVersion == CDM_MODULE_VERSION &&
- aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
- aHostVersion == cdm::Host_8::kVersion;
+ aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion &&
+ aHostVersion == cdm::Host_9::kVersion;
}
} // namespace mozilla
diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
index 149fa1701..4d3408804 100644
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -102,7 +102,7 @@ WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken,
} else {
// Invalid init data type
const char* errorMsg = "Invalid init data type when creating session.";
- OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg));
+ OnRejectPromise(aPromiseId, kExceptionNotSupportedError, 0, errorMsg, sizeof(errorMsg));
return;
}
mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken;
@@ -302,6 +302,12 @@ WidevineDecryptor::GetCurrentWallTime()
}
void
+WidevineDecryptor::OnResolveKeyStatusPromise(uint32_t aPromiseId,
+ cdm::KeyStatus aKeyStatus) {
+ //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230.
+}
+
+void
WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize)
@@ -333,41 +339,59 @@ WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId)
}
static GMPDOMException
-ToGMPDOMException(cdm::Error aError)
-{
- switch (aError) {
- case kNotSupportedError: return kGMPNotSupportedError;
- case kInvalidStateError: return kGMPInvalidStateError;
- case kInvalidAccessError:
- // Note: Chrome converts kInvalidAccessError to TypeError, since the
- // Chromium CDM API doesn't have a type error enum value. The EME spec
- // requires TypeError in some places, so we do the same conversion.
- // See bug 1313202.
- return kGMPTypeError;
- case kQuotaExceededError: return kGMPQuotaExceededError;
+ConvertCDMExceptionToGMPDOMException(cdm::Exception aException)
+{
+ switch (aException) {
+ case kExceptionNotSupportedError: return kGMPNotSupportedError;
+ case kExceptionInvalidStateError: return kGMPInvalidStateError;
+ case kExceptionTypeError: return kGMPTypeError;
+ case kExceptionQuotaExceededError: return kGMPQuotaExceededError;
case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder.
case kClientError: return kGMPAbortError; // Note: Unique placeholder.
case kOutputError: return kGMPSecurityError; // Note: Unique placeholder.
};
- return kGMPTimeoutError; // Note: Unique placeholder.
+ return kGMPInvalidStateError; // Note: Unique placeholder.
+}
+
+// Align with spec, the Exceptions used by CDM to reject promises .
+// https://w3c.github.io/encrypted-media/#exceptions
+cdm::Exception
+ConvertCDMErrorToCDMException(cdm::Error error) {
+ switch (error) {
+ case cdm::kNotSupportedError:
+ return cdm::Exception::kExceptionNotSupportedError;
+ case cdm::kInvalidStateError:
+ return cdm::Exception::kExceptionInvalidStateError;
+ case cdm::kInvalidAccessError:
+ return cdm::Exception::kExceptionTypeError;
+ case cdm::kQuotaExceededError:
+ return cdm::Exception::kExceptionQuotaExceededError;
+
+ case cdm::kUnknownError:
+ case cdm::kClientError:
+ case cdm::kOutputError:
+ break;
+ }
+
+ return cdm::Exception::kExceptionInvalidStateError;
}
void
WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId,
- Error aError,
+ cdm::Exception aException,
uint32_t aSystemCode,
const char* aErrorMessage,
uint32_t aErrorMessageSize)
{
if (!mCallback) {
Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback",
- aPromiseId, (int)aError, aSystemCode, aErrorMessage);
+ aPromiseId, (int)aException, aSystemCode, aErrorMessage);
return;
}
Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)",
- aPromiseId, (int)aError, aSystemCode, aErrorMessage);
+ aPromiseId, (int)aException, aSystemCode, aErrorMessage);
mCallback->RejectPromise(aPromiseId,
- ToGMPDOMException(aError),
+ ConvertCDMExceptionToGMPDOMException(aException),
!aErrorMessageSize ? "" : aErrorMessage,
aErrorMessageSize);
}
@@ -386,11 +410,9 @@ ToGMPMessageType(MessageType message_type)
void
WidevineDecryptor::OnSessionMessage(const char* aSessionId,
uint32_t aSessionIdSize,
- MessageType aMessageType,
+ cdm::MessageType aMessageType,
const char* aMessage,
- uint32_t aMessageSize,
- const char* aLegacyDestinationUrl,
- uint32_t aLegacyDestinationUrlLength)
+ uint32_t aMessageSize)
{
if (!mCallback) {
Log("Decryptor::OnSessionMessage() FAIL; !mCallback");
@@ -479,28 +501,6 @@ WidevineDecryptor::OnSessionClosed(const char* aSessionId,
}
void
-WidevineDecryptor::OnLegacySessionError(const char* aSessionId,
- uint32_t aSessionIdLength,
- Error aError,
- uint32_t aSystemCode,
- const char* aErrorMessage,
- uint32_t aErrorMessageLength)
-{
- if (!mCallback) {
- Log("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback",
- aSessionId, (int)aError);
- return;
- }
- Log("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError);
- mCallback->SessionError(aSessionId,
- aSessionIdLength,
- ToGMPDOMException(aError),
- aSystemCode,
- aErrorMessage,
- aErrorMessageLength);
-}
-
-void
WidevineDecryptor::SendPlatformChallenge(const char* aServiceId,
uint32_t aServiceIdSize,
const char* aChallenge,
@@ -538,4 +538,17 @@ WidevineDecryptor::CreateFileIO(FileIOClient* aClient)
return new WidevineFileIO(aClient);
}
+void
+WidevineDecryptor::RequestStorageId(uint32_t aVersion)
+{
+ Log("Decryptor::RequestStorageId() aVersion = %u", aVersion);
+ if (aVersion >= 0x80000000) {
+ mCDM->OnStorageId(aVersion, nullptr, 0);
+ return;
+ }
+
+ //TODO: Need to provide a menaingful buffer instead of a dummy one.
+ mCDM->OnStorageId(aVersion, new uint8_t[1024*1024], 1024 * 1024);
+}
+
} // namespace mozilla
diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
index d5185192b..f291c321d 100644
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
@@ -16,7 +16,7 @@
namespace mozilla {
class WidevineDecryptor : public GMPDecryptor
- , public cdm::Host_8
+ , public cdm::Host_9
{
public:
@@ -69,16 +69,19 @@ public:
void DecryptingComplete() override;
- // cdm::Host_8
+ // cdm::Host_9 implementation
cdm::Buffer* Allocate(uint32_t aCapacity) override;
void SetTimer(int64_t aDelayMs, void* aContext) override;
cdm::Time GetCurrentWallTime() override;
+ // cdm::Host_9 interface
+ void OnResolveKeyStatusPromise(uint32_t aPromiseId,
+ cdm::KeyStatus aKeyStatus) override;
void OnResolveNewSessionPromise(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize) override;
void OnResolvePromise(uint32_t aPromiseId) override;
void OnRejectPromise(uint32_t aPromiseId,
- cdm::Error aError,
+ cdm::Exception aException,
uint32_t aSystemCode,
const char* aErrorMessage,
uint32_t aErrorMessageSize) override;
@@ -86,9 +89,7 @@ public:
uint32_t aSessionIdSize,
cdm::MessageType aMessageType,
const char* aMessage,
- uint32_t aMessageSize,
- const char* aLegacyDestinationUrl,
- uint32_t aLegacyDestinationUrlLength) override;
+ uint32_t aMessageSize) override;
void OnSessionKeysChange(const char* aSessionId,
uint32_t aSessionIdSize,
bool aHasAdditionalUsableKey,
@@ -99,12 +100,6 @@ public:
cdm::Time aNewExpiryTime) override;
void OnSessionClosed(const char* aSessionId,
uint32_t aSessionIdSize) override;
- void OnLegacySessionError(const char* aSessionId,
- uint32_t aSessionId_length,
- cdm::Error aError,
- uint32_t aSystemCode,
- const char* aErrorMessage,
- uint32_t aErrorMessageLength) override;
void SendPlatformChallenge(const char* aServiceId,
uint32_t aServiceIdSize,
const char* aChallenge,
@@ -113,6 +108,9 @@ public:
void QueryOutputProtectionStatus() override;
void OnDeferredInitializationDone(cdm::StreamType aStreamType,
cdm::Status aDecoderStatus) override;
+ // cdm::Host_9 interface
+ // NOTE: the interface has changed upstream.
+ void RequestStorageId(uint32_t aVersion) override;
cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override;
GMPDecryptorCallback* Callback() const { return mCallback; }
@@ -120,7 +118,7 @@ public:
private:
~WidevineDecryptor();
RefPtr<CDMWrapper> mCDM;
- cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); }
+ cdm::ContentDecryptionModule_9* CDM() { return mCDM->GetCDM(); }
GMPDecryptorCallback* mCallback;
std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens;
diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp
index 925dfe1a1..10c6c2e18 100644
--- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp
@@ -43,7 +43,7 @@ ToGMPErr(cdm::Status aStatus)
case cdm::kSuccess: return GMPNoErr;
case cdm::kNeedMoreData: return GMPGenericErr;
case cdm::kNoKey: return GMPNoKeyErr;
- case cdm::kSessionError: return GMPGenericErr;
+ case cdm::kInitializationError: return GMPGenericErr;
case cdm::kDecryptError: return GMPCryptoErr;
case cdm::kDecodeError: return GMPDecodeErr;
case cdm::kDeferredInitialization: return GMPGenericErr;
@@ -77,7 +77,7 @@ void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto,
aInputBuffer.timestamp = aTimestamp;
}
-CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_8* aCDM,
+CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_9* aCDM,
WidevineDecryptor* aDecryptor)
: mCDM(aCDM)
, mDecryptor(aDecryptor)
diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.h b/dom/media/gmp/widevine-adapter/WidevineUtils.h
index 57c004a87..2f6137fe3 100644
--- a/dom/media/gmp/widevine-adapter/WidevineUtils.h
+++ b/dom/media/gmp/widevine-adapter/WidevineUtils.h
@@ -48,12 +48,16 @@ class CDMWrapper {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper)
- explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM,
+ explicit CDMWrapper(cdm::ContentDecryptionModule_9* aCDM,
WidevineDecryptor* aDecryptor);
- cdm::ContentDecryptionModule_8* GetCDM() const { return mCDM; }
+ cdm::ContentDecryptionModule_9* GetCDM() const { return mCDM; }
+ void OnStorageId(uint32_t aVersion, const uint8_t* aStorageId,
+ uint32_t aStorageIdSize) {
+ mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize);
+ }
private:
~CDMWrapper();
- cdm::ContentDecryptionModule_8* mCDM;
+ cdm::ContentDecryptionModule_9* mCDM;
RefPtr<WidevineDecryptor> mDecryptor;
};
diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
index b143f75f7..f5e63519b 100644
--- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
@@ -45,7 +45,7 @@ private:
~WidevineVideoDecoder();
- cdm::ContentDecryptionModule_8* CDM() const {
+ cdm::ContentDecryptionModule_9* CDM() const {
// CDM should only be accessed before 'DecodingComplete'.
MOZ_ASSERT(mCDMWrapper);
// CDMWrapper ensure the CDM is non-null, no need to check again.
diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h
index 512ca9768..0539135fb 100644
--- a/dom/media/gmp/widevine-adapter/content_decryption_module.h
+++ b/dom/media/gmp/widevine-adapter/content_decryption_module.h
@@ -5,6 +5,8 @@
#ifndef CDM_CONTENT_DECRYPTION_MODULE_H_
#define CDM_CONTENT_DECRYPTION_MODULE_H_
+#include "content_decryption_module_export.h"
+
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
@@ -14,25 +16,21 @@ typedef __int64 int64_t;
#include <stdint.h>
#endif
-// Define CDM_EXPORT so that functionality implemented by the CDM module
-// can be exported to consumers.
-#if defined(WIN32)
-
-#if defined(CDM_IMPLEMENTATION)
-#define CDM_EXPORT __declspec(dllexport)
-#else
-#define CDM_EXPORT __declspec(dllimport)
-#endif // defined(CDM_IMPLEMENTATION)
-
-#else // defined(WIN32)
-
-#if defined(CDM_IMPLEMENTATION)
-#define CDM_EXPORT __attribute__((visibility("default")))
+// Define CDM_CLASS_API to export class types. We have to add visibility
+// attributes to make sure virtual tables in CDM consumer and CDM implementation
+// are the same. Generally, it was always a good idea, as there're no guarantees
+// about that for the internal symbols, but it has only become a practical issue
+// after introduction of LTO devirtualization. See more details on
+// https://crbug.com/609564#c35
+#if defined(_WIN32)
+#if defined(__clang__)
+#define CDM_CLASS_API [[clang::lto_visibility_public]]
#else
-#define CDM_EXPORT
+#define CDM_CLASS_API
#endif
-
-#endif // defined(WIN32)
+#else // defined(_WIN32)
+#define CDM_CLASS_API __attribute__((visibility("default")))
+#endif // defined(_WIN32)
// The version number must be rolled when the exported functions are updated!
// If the CDM and the adapter use different versions of these functions, the
@@ -48,9 +46,9 @@ typedef __int64 int64_t;
#define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version
extern "C" {
-CDM_EXPORT void INITIALIZE_CDM_MODULE();
+CDM_API void INITIALIZE_CDM_MODULE();
-CDM_EXPORT void DeinitializeCdmModule();
+CDM_API void DeinitializeCdmModule();
// Returns a pointer to the requested CDM Host interface upon success.
// Returns NULL if the requested CDM Host interface is not supported.
@@ -65,30 +63,30 @@ typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data);
// |cdm_interface_version|.
// Caller retains ownership of arguments and must call Destroy() on the returned
// object.
-CDM_EXPORT void* CreateCdmInstance(
+CDM_API void* CreateCdmInstance(
int cdm_interface_version,
const char* key_system, uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func, void* user_data);
-CDM_EXPORT const char* GetCdmVersion();
+CDM_API const char* GetCdmVersion();
}
namespace cdm {
-class AudioFrames;
-class DecryptedBlock;
-class VideoFrame;
+class CDM_CLASS_API AudioFrames;
+class CDM_CLASS_API DecryptedBlock;
+class CDM_CLASS_API VideoFrame;
-class Host_7;
-class Host_8;
+class CDM_CLASS_API Host_8;
+class CDM_CLASS_API Host_9;
enum Status {
kSuccess = 0,
kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample.
- kNoKey, // The required decryption key is not available.
- kSessionError, // Session management error.
- kDecryptError, // Decryption failed.
- kDecodeError, // Error decoding audio or video.
+ kNoKey, // The required decryption key is not available.
+ kInitializationError, // Initialization error.
+ kDecryptError, // Decryption failed.
+ kDecodeError, // Error decoding audio or video.
kDeferredInitialization // Decoder is not ready for initialization.
};
@@ -97,6 +95,7 @@ enum Status {
// The following starts with the list of DOM4 exceptions from:
// http://www.w3.org/TR/dom/#domexception
// Some DOM4 exceptions are not included as they are not expected to be used.
+// Should only be used on Host_8 and before.
enum Error {
kNotSupportedError = 9,
kInvalidStateError = 11,
@@ -113,8 +112,20 @@ enum Error {
kOutputError = 101
};
-// Time is defined as the number of seconds since the
-// Epoch (00:00:00 UTC, January 1, 1970).
+// Exceptions used by the CDM to reject promises.
+// https://w3c.github.io/encrypted-media/#exceptions
+enum Exception {
+ kExceptionTypeError,
+ kExceptionNotSupportedError,
+ kExceptionInvalidStateError,
+ kExceptionQuotaExceededError
+};
+
+// Time is defined as the number of seconds since the Epoch
+// (00:00:00 UTC, January 1, 1970), not including any added leap second.
+// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time
+// Note that Time is defined in millisecond accuracy in the spec but in second
+// accuracy here.
typedef double Time;
// An input buffer can be split into several continuous subsamples.
@@ -151,13 +162,13 @@ struct SubsampleEntry {
// unencrypted.
struct InputBuffer {
InputBuffer()
- : data(NULL),
+ : data(nullptr),
data_size(0),
- key_id(NULL),
+ key_id(nullptr),
key_id_size(0),
- iv(NULL),
+ iv(nullptr),
iv_size(0),
- subsamples(NULL),
+ subsamples(nullptr),
num_subsamples(0),
timestamp(0) {}
@@ -188,7 +199,7 @@ struct AudioDecoderConfig {
channel_count(0),
bits_per_channel(0),
samples_per_second(0),
- extra_data(NULL),
+ extra_data(nullptr),
extra_data_size(0) {}
AudioCodec codec;
@@ -214,10 +225,25 @@ enum AudioFormat {
};
// Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php
+// Values are chosen to be consistent with Chromium's VideoPixelFormat values.
enum VideoFormat {
kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting.
- kYv12, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
- kI420 // 12bpp YVU planar 1x1 Y, 2x2 UV samples.
+ kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
+ kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples.
+
+ // In the following formats, each sample uses 16-bit in storage, while the
+ // sample value is stored in the least significant N bits where N is
+ // specified by the number after "P". For example, for YUV420P9, each Y, U,
+ // and V sample is stored in the least significant 9 bits in a 2-byte block.
+ kYUV420P9 = 16,
+ kYUV420P10 = 17,
+ kYUV422P9 = 18,
+ kYUV422P10 = 19,
+ kYUV444P9 = 20,
+ kYUV444P10 = 21,
+ kYUV420P12 = 22,
+ kYUV422P12 = 23,
+ kYUV444P12 = 24,
};
struct Size {
@@ -245,14 +271,19 @@ struct VideoDecoderConfig {
kH264ProfileHigh,
kH264ProfileHigh10,
kH264ProfileHigh422,
- kH264ProfileHigh444Predictive
+ kH264ProfileHigh444Predictive,
+ // VP9 Profiles are only passed in starting from CDM_9.
+ kVP9Profile0,
+ kVP9Profile1,
+ kVP9Profile2,
+ kVP9Profile3
};
VideoDecoderConfig()
: codec(kUnknownVideoCodec),
profile(kUnknownVideoCodecProfile),
format(kUnknownVideoFormat),
- extra_data(NULL),
+ extra_data(nullptr),
extra_data_size(0) {}
VideoCodec codec;
@@ -294,7 +325,7 @@ struct PlatformChallengeResponse {
// Used when passing arrays of binary data. Does not own the referenced data.
struct BinaryData {
- BinaryData() : data(NULL), length(0) {}
+ BinaryData() : data(nullptr), length(0) {}
const uint8_t* data;
uint32_t length;
};
@@ -316,7 +347,10 @@ enum KeyStatus {
// should be 0 when |status| == kUsable.
struct KeyInformation {
KeyInformation()
- : key_id(NULL), key_id_size(0), status(kInternalError), system_code(0) {}
+ : key_id(nullptr),
+ key_id_size(0),
+ status(kInternalError),
+ system_code(0) {}
const uint8_t* key_id;
uint32_t key_id_size;
KeyStatus status;
@@ -372,6 +406,24 @@ enum MessageType {
kLicenseRelease = 2
};
+enum HdcpVersion {
+ kHdcpVersionNone,
+ kHdcpVersion1_0,
+ kHdcpVersion1_1,
+ kHdcpVersion1_2,
+ kHdcpVersion1_3,
+ kHdcpVersion1_4,
+ kHdcpVersion2_0,
+ kHdcpVersion2_1,
+ kHdcpVersion2_2
+};
+
+struct Policy {
+ Policy() : min_hdcp_version(kHdcpVersionNone) {}
+
+ HdcpVersion min_hdcp_version;
+};
+
// FileIO interface provides a way for the CDM to store data in a file in
// persistent storage. This interface aims only at providing basic read/write
// capabilities and should not be used as a full fledged file IO API.
@@ -381,7 +433,7 @@ enum MessageType {
// Note to implementors of this interface:
// Per-origin storage and the ability for users to clear it are important.
// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
-class FileIO {
+class CDM_CLASS_API FileIO {
public:
// Opens the file with |file_name| for read and write.
// FileIOClient::OnOpenComplete() will be called after the opening
@@ -389,8 +441,9 @@ class FileIO {
// - When the file is opened by a CDM instance, it will be classified as "in
// use". In this case other CDM instances in the same domain may receive
// kInUse status when trying to open it.
- // - |file_name| must not contain forward slash ('/') or backslash ('\'), and
- // must not start with an underscore ('_').
+ // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-".
+ // It must not start with an underscore ('_'), and must be at least 1
+ // character and no more than 256 characters long.
virtual void Open(const char* file_name, uint32_t file_name_size) = 0;
// Reads the contents of the file. FileIOClient::OnReadComplete() will be
@@ -421,7 +474,7 @@ class FileIO {
// When kError is returned, the FileIO object could be in an error state. All
// following calls (other than Close()) could return kError. The CDM should
// still call Close() to destroy the FileIO object.
-class FileIOClient {
+class CDM_CLASS_API FileIOClient {
public:
enum Status {
kSuccess = 0,
@@ -462,10 +515,20 @@ class FileIOClient {
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
-class ContentDecryptionModule_7 {
+class CDM_CLASS_API ContentDecryptionModule_8 {
public:
- static const int kVersion = 7;
- typedef Host_7 Host;
+ static const int kVersion = 8;
+ typedef Host_8 Host;
+
+ // Initializes the CDM instance, providing information about permitted
+ // functionalities.
+ // If |allow_distinctive_identifier| is false, messages from the CDM,
+ // such as message events, must not contain a Distinctive Identifier,
+ // even in an encrypted form.
+ // If |allow_persistent_state| is false, the CDM must not attempt to
+ // persist state. Calls to CreateFileIO() will fail.
+ virtual void Initialize(bool allow_distinctive_identifier,
+ bool allow_persistent_state) = 0;
// SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
// UpdateSession(), CloseSession(), and RemoveSession() all accept a
@@ -484,8 +547,7 @@ class ContentDecryptionModule_7 {
// or Host::OnRejectPromise().
virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
SessionType session_type,
- const char* init_data_type,
- uint32_t init_data_type_size,
+ InitDataType init_data_type,
const uint8_t* init_data,
uint32_t init_data_size) = 0;
@@ -631,8 +693,8 @@ class ContentDecryptionModule_7 {
virtual void Destroy() = 0;
protected:
- ContentDecryptionModule_7() {}
- virtual ~ContentDecryptionModule_7() {}
+ ContentDecryptionModule_8() {}
+ virtual ~ContentDecryptionModule_8() {}
};
// ContentDecryptionModule interface that all CDMs need to implement.
@@ -641,10 +703,10 @@ class ContentDecryptionModule_7 {
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
-class ContentDecryptionModule_8 {
+class CDM_CLASS_API ContentDecryptionModule_9 {
public:
- static const int kVersion = 8;
- typedef Host_8 Host;
+ static const int kVersion = 9;
+ typedef Host_9 Host;
// Initializes the CDM instance, providing information about permitted
// functionalities.
@@ -656,6 +718,13 @@ class ContentDecryptionModule_8 {
virtual void Initialize(bool allow_distinctive_identifier,
bool allow_persistent_state) = 0;
+ // Gets the key status if the CDM has a hypothetical key with the |policy|.
+ // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
+ // with the result key status or Host::OnRejectPromise() if an unexpected
+ // error happened or this method is not supported.
+ virtual void GetStatusForPolicy(uint32_t promise_id,
+ const Policy& policy) = 0;
+
// SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
// UpdateSession(), CloseSession(), and RemoveSession() all accept a
// |promise_id|, which must be passed to the completion Host method
@@ -731,8 +800,8 @@ class ContentDecryptionModule_8 {
//
// Returns kSuccess if the |audio_decoder_config| is supported and the CDM
// audio decoder is successfully initialized.
- // Returns kSessionError if |audio_decoder_config| is not supported. The CDM
- // may still be able to do Decrypt().
+ // Returns kInitializationError if |audio_decoder_config| is not supported.
+ // The CDM may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
@@ -744,8 +813,8 @@ class ContentDecryptionModule_8 {
//
// Returns kSuccess if the |video_decoder_config| is supported and the CDM
// video decoder is successfully initialized.
- // Returns kSessionError if |video_decoder_config| is not supported. The CDM
- // may still be able to do Decrypt().
+ // Returns kInitializationError if |video_decoder_config| is not supported.
+ // The CDM may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
@@ -815,18 +884,30 @@ class ContentDecryptionModule_8 {
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
+ // Called by the host after a call to Host::RequestStorageId(). If the
+ // version of the storage ID requested is available, |storage_id| and
+ // |storage_id_size| are set appropriately. |version| will be the same as
+ // what was requested, unless 0 (latest) was requested, in which case
+ // |version| will be the actual version number for the |storage_id| returned.
+ // If the requested version is not available, null/zero will be provided as
+ // |storage_id| and |storage_id_size|, respectively, and |version| should be
+ // ignored.
+ virtual void OnStorageId(uint32_t version,
+ const uint8_t* storage_id,
+ uint32_t storage_id_size) = 0;
+
// Destroys the object in the same context as it was created.
virtual void Destroy() = 0;
protected:
- ContentDecryptionModule_8() {}
- virtual ~ContentDecryptionModule_8() {}
+ ContentDecryptionModule_9() {}
+ virtual ~ContentDecryptionModule_9() {}
};
-typedef ContentDecryptionModule_8 ContentDecryptionModule;
+typedef ContentDecryptionModule_9 ContentDecryptionModule;
// Represents a buffer created by Allocator implementations.
-class Buffer {
+class CDM_CLASS_API Buffer {
public:
// Destroys the buffer in the same context as it was created.
virtual void Destroy() = 0;
@@ -845,9 +926,9 @@ class Buffer {
void operator=(const Buffer&);
};
-class Host_7 {
+class CDM_CLASS_API Host_8 {
public:
- static const int kVersion = 7;
+ static const int kVersion = 8;
// Returns a Buffer* containing non-zero members upon success, or NULL on
// failure. The caller owns the Buffer* after this call. The buffer is not
@@ -859,7 +940,7 @@ class Host_7 {
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
- // Returns the current wall time in seconds.
+ // Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
// Called by the CDM when a session is created or loaded and the value for the
@@ -917,8 +998,10 @@ class Host_7 {
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
- // can be 0 to represent "undefined". Size parameter should not include
- // null termination.
+ // represents the time after which the key(s) in the session will no longer
+ // be usable for decryption. It can be 0 if no such time exists or if the
+ // license explicitly never expires. Size parameter should not include null
+ // termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
@@ -978,13 +1061,13 @@ class Host_7 {
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
protected:
- Host_7() {}
- virtual ~Host_7() {}
+ Host_8() {}
+ virtual ~Host_8() {}
};
-class Host_8 {
+class CDM_CLASS_API Host_9 {
public:
- static const int kVersion = 8;
+ static const int kVersion = 9;
// Returns a Buffer* containing non-zero members upon success, or NULL on
// failure. The caller owns the Buffer* after this call. The buffer is not
@@ -996,9 +1079,14 @@ class Host_8 {
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
- // Returns the current wall time in seconds.
+ // Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
+ // Called by the CDM when a key status is available in response to
+ // GetStatusForPolicy().
+ virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
+ KeyStatus key_status) = 0;
+
// Called by the CDM when a session is created or loaded and the value for the
// MediaKeySession's sessionId attribute is available (|session_id|).
// This must be called before OnSessionMessage() or
@@ -1016,26 +1104,21 @@ class Host_8 {
// Called by the CDM when an error occurs as a result of one of the
// ContentDecryptionModule calls that accept a |promise_id|.
- // |error| must be specified, |error_message| and |system_code|
+ // |exception| must be specified. |error_message| and |system_code|
// are optional. |error_message_size| should not include null termination.
virtual void OnRejectPromise(uint32_t promise_id,
- Error error,
+ Exception exception,
uint32_t system_code,
const char* error_message,
uint32_t error_message_size) = 0;
// Called by the CDM when it has a message for session |session_id|.
// Size parameters should not include null termination.
- // |legacy_destination_url| is only for supporting the prefixed EME API and
- // is ignored by unprefixed EME. It should only be non-null if |message_type|
- // is kLicenseRenewal.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type,
const char* message,
- uint32_t message_size,
- const char* legacy_destination_url,
- uint32_t legacy_destination_url_length) = 0;
+ uint32_t message_size) = 0;
// Called by the CDM when there has been a change in keys or their status for
// session |session_id|. |has_additional_usable_key| should be set if a
@@ -1054,8 +1137,10 @@ class Host_8 {
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
- // can be 0 to represent "undefined". Size parameter should not include
- // null termination.
+ // represents the time after which the key(s) in the session will no longer
+ // be usable for decryption. It can be 0 if no such time exists or if the
+ // license explicitly never expires. Size parameter should not include null
+ // termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
@@ -1065,21 +1150,6 @@ class Host_8 {
virtual void OnSessionClosed(const char* session_id,
uint32_t session_id_size) = 0;
- // Called by the CDM when an error occurs in session |session_id|
- // unrelated to one of the ContentDecryptionModule calls that accept a
- // |promise_id|. |error| must be specified, |error_message| and
- // |system_code| are optional. Length parameters should not include null
- // termination.
- // Note:
- // - This method is only for supporting prefixed EME API.
- // - This method will be ignored by unprefixed EME. All errors reported
- // in this method should probably also be reported by one of other methods.
- virtual void OnLegacySessionError(
- const char* session_id, uint32_t session_id_length,
- Error error,
- uint32_t system_code,
- const char* error_message, uint32_t error_message_length) = 0;
-
// The following are optional methods that may not be implemented on all
// platforms.
@@ -1114,13 +1184,22 @@ class Host_8 {
// CDM can call this method multiple times to operate on different files.
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
+ // Requests a specific version of the storage ID. A storage ID is a stable,
+ // device specific ID used by the CDM to securely store persistent data. The
+ // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
+ // If |version| is 0, the latest version will be returned. All |version|s
+ // that are greater than or equal to 0x80000000 are reserved for the CDM and
+ // should not be supported or returned by the host. The CDM must not expose
+ // the ID outside the client device, even in encrypted form.
+ virtual void RequestStorageId(uint32_t version) = 0;
+
protected:
- Host_8() {}
- virtual ~Host_8() {}
+ Host_9() {}
+ virtual ~Host_9() {}
};
// Represents a decrypted block that has not been decoded.
-class DecryptedBlock {
+class CDM_CLASS_API DecryptedBlock {
public:
virtual void SetDecryptedBuffer(Buffer* buffer) = 0;
virtual Buffer* DecryptedBuffer() = 0;
@@ -1135,7 +1214,7 @@ class DecryptedBlock {
virtual ~DecryptedBlock() {}
};
-class VideoFrame {
+class CDM_CLASS_API VideoFrame {
public:
enum VideoPlane {
kYPlane = 0,
@@ -1178,7 +1257,7 @@ class VideoFrame {
//
// |<----------------- AudioFrames ------------------>|
// | audio buffer 0 | audio buffer 1 | audio buffer 2 |
-class AudioFrames {
+class CDM_CLASS_API AudioFrames {
public:
virtual void SetFrameBuffer(Buffer* buffer) = 0;
virtual Buffer* FrameBuffer() = 0;
diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h
new file mode 100644
index 000000000..51d485892
--- /dev/null
+++ b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h
@@ -0,0 +1,22 @@
+// Copyright 2017 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 CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
+#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
+
+// Define CDM_API so that functionality implemented by the CDM module
+// can be exported to consumers.
+#if defined(_WIN32)
+
+#if defined(CDM_IMPLEMENTATION)
+#define CDM_API __declspec(dllexport)
+#else
+#define CDM_API __declspec(dllimport)
+#endif // defined(CDM_IMPLEMENTATION)
+
+#else // defined(_WIN32)
+#define CDM_API __attribute__((visibility("default")))
+#endif // defined(_WIN32)
+
+#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h
new file mode 100644
index 000000000..5df8344e6
--- /dev/null
+++ b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h
@@ -0,0 +1,64 @@
+// Copyright 2017 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 CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
+#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include "content_decryption_module_export.h"
+
+#if defined(_MSC_VER)
+typedef unsigned int uint32_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace cdm {
+
+#if defined(_WIN32)
+typedef wchar_t FilePathCharType;
+typedef HANDLE PlatformFile;
+const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE;
+#else
+typedef char FilePathCharType;
+typedef int PlatformFile;
+const PlatformFile kInvalidPlatformFile = -1;
+#endif // defined(_WIN32)
+
+struct HostFile {
+ HostFile(const FilePathCharType* file_path,
+ PlatformFile file,
+ PlatformFile sig_file)
+ : file_path(file_path), file(file), sig_file(sig_file) {}
+
+ // File that is part of the host of the CDM.
+ const FilePathCharType* file_path = nullptr;
+ PlatformFile file = kInvalidPlatformFile;
+
+ // Signature file for |file|.
+ PlatformFile sig_file = kInvalidPlatformFile;
+};
+
+} // namespace cdm
+
+extern "C" {
+
+// Functions in this file are dynamically retrieved by their versioned function
+// names. Increment the version number for any backward incompatible API
+// changes.
+
+// Verifies CDM host. All files in |host_files| are opened in read-only mode.
+//
+// Returns false and closes all files if there is an immediate failure.
+// Otherwise returns true as soon as possible and processes the files
+// asynchronously. All files MUST be closed by the CDM after this one-time
+// processing is finished.
+CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files,
+ uint32_t num_files);
+}
+
+#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_