icecat: update to upstream version 128.0.14-1gnu1

This commit is contained in:
Ark74 2025-08-20 11:58:34 -06:00
parent 0cdda4f34e
commit 56c3deff60
77 changed files with 8997 additions and 3862 deletions

View file

@ -7,7 +7,6 @@
#include "GLContext.h"
#include "ImageBitmapRenderingContext.h"
#include "ImageEncoder.h"
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/OffscreenCanvasRenderingContext2D.h"
#include "mozilla/GfxMessageUtils.h"
@ -26,55 +25,6 @@ namespace mozilla::dom {
CanvasRenderingContextHelper::CanvasRenderingContextHelper()
: mCurrentContextType(CanvasContextType::NoContext) {}
void CanvasRenderingContextHelper::ToBlob(
JSContext* aCx, nsIGlobalObject* aGlobal, BlobCallback& aCallback,
const nsAString& aType, JS::Handle<JS::Value> aParams, bool aUsePlaceholder,
ErrorResult& aRv) {
// Encoder callback when encoding is complete.
class EncodeCallback : public EncodeCompleteCallback {
public:
EncodeCallback(nsIGlobalObject* aGlobal, BlobCallback* aCallback)
: mGlobal(aGlobal), mBlobCallback(aCallback) {}
// This is called on main thread.
MOZ_CAN_RUN_SCRIPT
nsresult ReceiveBlobImpl(already_AddRefed<BlobImpl> aBlobImpl) override {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<BlobImpl> blobImpl = aBlobImpl;
RefPtr<Blob> blob;
if (blobImpl) {
blob = Blob::Create(mGlobal, blobImpl);
}
RefPtr<BlobCallback> callback(std::move(mBlobCallback));
ErrorResult rv;
callback->Call(blob, rv);
mGlobal = nullptr;
MOZ_ASSERT(!mBlobCallback);
return rv.StealNSResult();
}
bool CanBeDeletedOnAnyThread() override {
// EncodeCallback is used from the main thread only.
return false;
}
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<BlobCallback> mBlobCallback;
};
RefPtr<EncodeCompleteCallback> callback =
new EncodeCallback(aGlobal, &aCallback);
ToBlob(aCx, callback, aType, aParams, aUsePlaceholder, aRv);
}
void CanvasRenderingContextHelper::ToBlob(
JSContext* aCx, EncodeCompleteCallback* aCallback, const nsAString& aType,
JS::Handle<JS::Value> aParams, bool aUsePlaceholder, ErrorResult& aRv) {

View file

@ -54,10 +54,6 @@ class CanvasRenderingContextHelper {
nsAString& outParams,
bool* const outCustomParseOptions);
void ToBlob(JSContext* aCx, nsIGlobalObject* global, BlobCallback& aCallback,
const nsAString& aType, JS::Handle<JS::Value> aParams,
bool aUsePlaceholder, ErrorResult& aRv);
void ToBlob(JSContext* aCx, EncodeCompleteCallback* aCallback,
const nsAString& aType, JS::Handle<JS::Value> aParams,
bool aUsePlaceholder, ErrorResult& aRv);

View file

@ -570,6 +570,10 @@ void OffscreenCanvas::SetWriteOnly(RefPtr<nsIPrincipal>&& aExpandedReader) {
mExpandedReader.forget());
mExpandedReader = std::move(aExpandedReader);
mIsWriteOnly = true;
if (mDisplay) {
mDisplay->SetWriteOnly(mExpandedReader);
}
}
bool OffscreenCanvas::CallerCanRead(nsIPrincipal& aPrincipal) const {

View file

@ -32,7 +32,11 @@ OffscreenCanvasDisplayHelper::OffscreenCanvasDisplayHelper(
mData.mSize.height = aHeight;
}
OffscreenCanvasDisplayHelper::~OffscreenCanvasDisplayHelper() = default;
OffscreenCanvasDisplayHelper::~OffscreenCanvasDisplayHelper() {
MutexAutoLock lock(mMutex);
NS_ReleaseOnMainThread("OffscreenCanvas::mExpandedReader",
mExpandedReader.forget());
}
void OffscreenCanvasDisplayHelper::DestroyElement() {
MOZ_ASSERT(NS_IsMainThread());
@ -61,6 +65,32 @@ void OffscreenCanvasDisplayHelper::DestroyCanvas() {
mWorkerRef = nullptr;
}
void OffscreenCanvasDisplayHelper::SetWriteOnly(nsIPrincipal* aExpandedReader) {
MutexAutoLock lock(mMutex);
NS_ReleaseOnMainThread("OffscreenCanvasDisplayHelper::mExpandedReader",
mExpandedReader.forget());
mExpandedReader = aExpandedReader;
mIsWriteOnly = true;
}
bool OffscreenCanvasDisplayHelper::CallerCanRead(
nsIPrincipal& aPrincipal) const {
MutexAutoLock lock(mMutex);
if (!mIsWriteOnly) {
return true;
}
// If mExpandedReader is set, this canvas was tainted only by
// mExpandedReader's resources. So allow reading if the subject
// principal subsumes mExpandedReader.
if (mExpandedReader && aPrincipal.Subsumes(mExpandedReader)) {
return true;
}
return nsContentUtils::PrincipalHasPermission(aPrincipal,
nsGkAtoms::all_urlsPermission);
}
bool OffscreenCanvasDisplayHelper::CanElementCaptureStream() const {
MutexAutoLock lock(mMutex);
return !!mWorkerRef;

View file

@ -57,6 +57,19 @@ class OffscreenCanvasDisplayHelper final {
void DestroyCanvas();
void DestroyElement();
bool IsWriteOnly() const {
MutexAutoLock lock(mMutex);
return mIsWriteOnly;
}
bool HasWorkerRef() const {
MutexAutoLock lock(mMutex);
return !!mWorkerRef;
}
void SetWriteOnly(nsIPrincipal* aExpandedReader = nullptr);
bool CallerCanRead(nsIPrincipal& aPrincipal) const;
bool CanElementCaptureStream() const;
bool UsingElementCaptureStream() const;
@ -90,6 +103,8 @@ class OffscreenCanvasDisplayHelper final {
mozilla::layers::ImageContainer::FrameID mLastFrameID MOZ_GUARDED_BY(mMutex) =
0;
bool mPendingInvalidate MOZ_GUARDED_BY(mMutex) = false;
bool mIsWriteOnly MOZ_GUARDED_BY(mMutex) = false;
RefPtr<nsIPrincipal> mExpandedReader MOZ_GUARDED_BY(mMutex);
};
} // namespace mozilla::dom

View file

@ -15,6 +15,7 @@
#include "mozilla/BasePrincipal.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/dom/CanvasCaptureMediaStream.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/Document.h"
@ -768,16 +769,26 @@ void HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
nsAString& aDataURL,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv) {
// mWriteOnly check is redundant, but optimizes for the common case.
if (mWriteOnly && !CallerCanRead(aSubjectPrincipal)) {
bool recheckCanRead = mOffscreenDisplay && mOffscreenDisplay->HasWorkerRef();
if (!CallerCanRead(aSubjectPrincipal)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsresult rv = ToDataURLImpl(aCx, aSubjectPrincipal, aType, aParams, aDataURL);
if (NS_FAILED(rv)) {
aDataURL.AssignLiteral("data:,");
nsString dataURL;
nsresult rv = ToDataURLImpl(aCx, aSubjectPrincipal, aType, aParams, dataURL);
if (recheckCanRead && !CallerCanRead(aSubjectPrincipal)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
if (NS_FAILED(rv)) {
aDataURL.Assign(u"data:,"_ns);
return;
}
aDataURL = std::move(dataURL);
}
void HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback) {
@ -993,8 +1004,9 @@ void HTMLCanvasElement::ToBlob(JSContext* aCx, BlobCallback& aCallback,
JS::Handle<JS::Value> aParams,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv) {
// mWriteOnly check is redundant, but optimizes for the common case.
if (mWriteOnly && !CallerCanRead(aSubjectPrincipal)) {
bool recheckCanRead = mOffscreenDisplay && mOffscreenDisplay->HasWorkerRef();
if (!CallerCanRead(aSubjectPrincipal)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -1019,7 +1031,59 @@ void HTMLCanvasElement::ToBlob(JSContext* aCx, BlobCallback& aCallback,
// If no permission, return all-white, opaque image data.
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(
OwnerDoc(), aCx, aSubjectPrincipal);
CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType, aParams,
// Encoder callback when encoding is complete.
class EncodeCallback : public EncodeCompleteCallback {
public:
EncodeCallback(nsIGlobalObject* aGlobal, BlobCallback* aCallback,
OffscreenCanvasDisplayHelper* aOffscreenDisplay,
nsIPrincipal* aSubjectPrincipal)
: mGlobal(aGlobal),
mBlobCallback(aCallback),
mOffscreenDisplay(aOffscreenDisplay),
mSubjectPrincipal(aSubjectPrincipal) {}
// This is called on main thread.
MOZ_CAN_RUN_SCRIPT
nsresult ReceiveBlobImpl(already_AddRefed<BlobImpl> aBlobImpl) override {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<BlobImpl> blobImpl = aBlobImpl;
RefPtr<Blob> blob;
if (blobImpl && (!mOffscreenDisplay ||
mOffscreenDisplay->CallerCanRead(*mSubjectPrincipal))) {
blob = Blob::Create(mGlobal, blobImpl);
}
RefPtr<BlobCallback> callback(std::move(mBlobCallback));
ErrorResult rv;
callback->Call(blob, rv);
mGlobal = nullptr;
MOZ_ASSERT(!mBlobCallback);
return rv.StealNSResult();
}
bool CanBeDeletedOnAnyThread() override {
// EncodeCallback is used from the main thread only.
return false;
}
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<BlobCallback> mBlobCallback;
RefPtr<OffscreenCanvasDisplayHelper> mOffscreenDisplay;
RefPtr<nsIPrincipal> mSubjectPrincipal;
};
RefPtr<EncodeCompleteCallback> callback = new EncodeCallback(
global, &aCallback, recheckCanRead ? mOffscreenDisplay.get() : nullptr,
recheckCanRead ? &aSubjectPrincipal : nullptr);
CanvasRenderingContextHelper::ToBlob(aCx, callback, aType, aParams,
usePlaceholder, aRv);
}
@ -1090,7 +1154,12 @@ already_AddRefed<nsISupports> HTMLCanvasElement::GetContext(
nsIntSize HTMLCanvasElement::GetSize() { return GetWidthHeight(); }
bool HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly; }
bool HTMLCanvasElement::IsWriteOnly() const {
if (mOffscreenDisplay && mOffscreenDisplay->IsWriteOnly()) {
return true;
}
return mWriteOnly;
}
void HTMLCanvasElement::SetWriteOnly(
nsIPrincipal* aExpandedReader /* = nullptr */) {
@ -1102,6 +1171,10 @@ void HTMLCanvasElement::SetWriteOnly(
}
bool HTMLCanvasElement::CallerCanRead(nsIPrincipal& aPrincipal) const {
if (mOffscreenDisplay && !mOffscreenDisplay->CallerCanRead(aPrincipal)) {
return false;
}
if (!mWriteOnly) {
return true;
}

View file

@ -372,13 +372,13 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
RefPtr<layers::ImageContainer> mImageContainer;
RefPtr<HTMLCanvasElementObserver> mContextObserver;
public:
// Record whether this canvas should be write-only or not.
// We set this when script paints an image from a different origin.
// We also transitively set it when script paints a canvas which
// is itself write-only.
bool mWriteOnly;
public:
// When this canvas is (only) tainted by an image from an extension
// content script, allow reads from the same extension afterwards.
RefPtr<nsIPrincipal> mExpandedReader;

View file

@ -96,9 +96,7 @@ void ClearKeyPersistence::WriteIndex() {
std::move(onIndexFail));
}
ClearKeyPersistence::ClearKeyPersistence(Host_10* aHost) {
this->mHost = aHost;
}
ClearKeyPersistence::ClearKeyPersistence(Host_11* aHost) : mHost(aHost) {}
void ClearKeyPersistence::EnsureInitialized(bool aPersistentStateAllowed,
function<void()>&& aOnInitialized) {

View file

@ -37,7 +37,7 @@ enum PersistentKeyState { UNINITIALIZED, LOADING, LOADED };
class ClearKeyPersistence : public RefCounted {
public:
explicit ClearKeyPersistence(cdm::Host_10* aHost);
explicit ClearKeyPersistence(cdm::Host_11* aHost);
void EnsureInitialized(bool aPersistentStateAllowed,
std::function<void()>&& aOnInitialized);
@ -51,7 +51,7 @@ class ClearKeyPersistence : public RefCounted {
void PersistentSessionRemoved(std::string& aSid);
private:
cdm::Host_10* mHost = nullptr;
cdm::Host_11* mHost = nullptr;
PersistentKeyState mPersistentKeyState = PersistentKeyState::UNINITIALIZED;

View file

@ -35,7 +35,7 @@ using std::function;
using std::string;
using std::vector;
ClearKeySessionManager::ClearKeySessionManager(Host_10* aHost)
ClearKeySessionManager::ClearKeySessionManager(Host_11* aHost)
: mDecryptionManager(ClearKeyDecryptionManager::Get()) {
CK_LOGD("ClearKeySessionManager ctor %p", this);
AddRef();

View file

@ -39,7 +39,7 @@
class ClearKeySessionManager final : public RefCounted {
public:
explicit ClearKeySessionManager(cdm::Host_10* aHost);
explicit ClearKeySessionManager(cdm::Host_11* aHost);
void Init(bool aDistinctiveIdentifierAllowed, bool aPersistentStateAllowed);
@ -116,7 +116,7 @@ class ClearKeySessionManager final : public RefCounted {
RefPtr<ClearKeyDecryptionManager> mDecryptionManager;
RefPtr<ClearKeyPersistence> mPersistence;
cdm::Host_10* mHost = nullptr;
cdm::Host_11* mHost = nullptr;
std::set<KeyId> mKeyIds;
std::map<std::string, ClearKeySession*> mSessions;

View file

@ -40,7 +40,7 @@ class WriteRecordClient : public FileIOClient {
* This function will take the memory ownership of the parameters and
* delete them when done.
*/
static void Write(Host_10* aHost, string& aRecordName,
static void Write(Host_11* aHost, string& aRecordName,
const vector<uint8_t>& aData, function<void()>&& aOnSuccess,
function<void()>&& aOnFailure) {
WriteRecordClient* client = new WriteRecordClient(
@ -75,7 +75,7 @@ class WriteRecordClient : public FileIOClient {
mOnFailure(std::move(aOnFailure)),
mData(aData) {}
void Do(const string& aName, Host_10* aHost) {
void Do(const string& aName, Host_11* aHost) {
// Initialize the FileIO.
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
@ -108,7 +108,7 @@ class WriteRecordClient : public FileIOClient {
const vector<uint8_t> mData;
};
void WriteData(Host_10* aHost, string& aRecordName,
void WriteData(Host_11* aHost, string& aRecordName,
const vector<uint8_t>& aData, function<void()>&& aOnSuccess,
function<void()>&& aOnFailure) {
WriteRecordClient::Write(aHost, aRecordName, aData, std::move(aOnSuccess),
@ -121,7 +121,7 @@ class ReadRecordClient : public FileIOClient {
* This function will take the memory ownership of the parameters and
* delete them when done.
*/
static void Read(Host_10* aHost, string& aRecordName,
static void Read(Host_11* aHost, string& aRecordName,
function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
function<void()>&& aOnFailure) {
(new ReadRecordClient(std::move(aOnSuccess), std::move(aOnFailure)))
@ -155,7 +155,7 @@ class ReadRecordClient : public FileIOClient {
mOnSuccess(std::move(aOnSuccess)),
mOnFailure(std::move(aOnFailure)) {}
void Do(const string& aName, Host_10* aHost) {
void Do(const string& aName, Host_11* aHost) {
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
}
@ -186,7 +186,7 @@ class ReadRecordClient : public FileIOClient {
function<void()> mOnFailure;
};
void ReadData(Host_10* aHost, string& aRecordName,
void ReadData(Host_11* aHost, string& aRecordName,
function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
function<void()>&& aOnFailure) {
ReadRecordClient::Read(aHost, aRecordName, std::move(aOnSuccess),

View file

@ -29,13 +29,13 @@
#define IO_FAILED(x) ((x) != cdm::FileIOClient::Status::kSuccess)
// Writes data to a file and fires the appropriate callback when complete.
void WriteData(cdm::Host_10* aHost, std::string& aRecordName,
void WriteData(cdm::Host_11* aHost, std::string& aRecordName,
const std::vector<uint8_t>& aData,
std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure);
// Reads data from a file and fires the appropriate callback when complete.
void ReadData(cdm::Host_10* aHost, std::string& aRecordName,
void ReadData(cdm::Host_11* aHost, std::string& aRecordName,
std::function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
std::function<void()>&& aOnFailure);

View file

@ -46,11 +46,11 @@ 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) {
if (cdm_interface_version != cdm::ContentDecryptionModule_10::kVersion) {
// Only support CDM version 10 currently.
if (cdm_interface_version != cdm::ContentDecryptionModule_11::kVersion) {
// Only support CDM version 11 currently.
return nullptr;
}
cdm::Host_10* host = static_cast<cdm::Host_10*>(
cdm::Host_11* host = static_cast<cdm::Host_11*>(
get_cdm_host_func(cdm_interface_version, user_data));
return new FakeDecryptor(host);
}

View file

@ -67,7 +67,7 @@ class TestManager {
std::set<std::string> mTestIDs;
};
FakeDecryptor::FakeDecryptor(cdm::Host_10* aHost) : mHost(aHost) {
FakeDecryptor::FakeDecryptor(cdm::Host_11* aHost) : mHost(aHost) {
MOZ_ASSERT(!sInstance);
sInstance = this;
}

View file

@ -11,7 +11,7 @@
class FakeDecryptor : public cdm::ContentDecryptionModule_10 {
public:
explicit FakeDecryptor(cdm::Host_10* aHost);
explicit FakeDecryptor(cdm::Host_11* aHost);
void Initialize(bool aAllowDistinctiveIdentifier, bool aAllowPersistentState,
bool aUseHardwareSecureCodecs) override {
@ -93,7 +93,7 @@ class FakeDecryptor : public cdm::ContentDecryptionModule_10 {
static void Message(const std::string& aMessage);
cdm::Host_10* mHost;
cdm::Host_11* mHost;
static FakeDecryptor* sInstance;

View file

@ -31,7 +31,7 @@ class WriteRecordClient : public FileIOClient {
void OnWriteComplete(Status aStatus) override { Done(aStatus); }
void Do(const std::string& aName, Host_10* aHost) {
void Do(const std::string& aName, Host_11* aHost) {
// Initialize the FileIO.
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
@ -64,7 +64,7 @@ class WriteRecordClient : public FileIOClient {
std::vector<uint8_t> mData;
};
void WriteRecord(Host_10* aHost, const std::string& aRecordName,
void WriteRecord(Host_11* aHost, const std::string& aRecordName,
const uint8_t* aData, uint32_t aNumBytes,
std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure) {
@ -74,7 +74,7 @@ void WriteRecord(Host_10* aHost, const std::string& aRecordName,
client->Do(aRecordName, aHost);
}
void WriteRecord(Host_10* aHost, const std::string& aRecordName,
void WriteRecord(Host_11* aHost, const std::string& aRecordName,
const std::string& aData, std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure) {
return WriteRecord(aHost, aRecordName, (const uint8_t*)aData.c_str(),
@ -104,7 +104,7 @@ class ReadRecordClient : public FileIOClient {
void OnWriteComplete(Status aStatus) override {}
void Do(const std::string& aName, Host_10* aHost) {
void Do(const std::string& aName, Host_11* aHost) {
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
}
@ -136,7 +136,7 @@ class ReadRecordClient : public FileIOClient {
};
void ReadRecord(
Host_10* aHost, const std::string& aRecordName,
Host_11* aHost, const std::string& aRecordName,
std::function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete) {
// client will be delete in ReadRecordClient::Done
ReadRecordClient* client = new ReadRecordClient(std::move(aOnReadComplete));
@ -155,7 +155,7 @@ class OpenRecordClient : public FileIOClient {
void OnWriteComplete(Status aStatus) override {}
void Do(const std::string& aName, Host_10* aHost) {
void Do(const std::string& aName, Host_11* aHost) {
// Initialize the FileIO.
mFileIO = aHost->CreateFileIO(this);
mFileIO->Open(aName.c_str(), aName.size());
@ -186,7 +186,7 @@ class OpenRecordClient : public FileIOClient {
std::function<void(bool)> mOpenComplete;
};
void OpenRecord(Host_10* aHost, const std::string& aRecordName,
void OpenRecord(Host_11* aHost, const std::string& aRecordName,
std::function<void(bool)>&& aOpenComplete) {
// client will be delete in OpenRecordClient::Done
OpenRecordClient* client = new OpenRecordClient(std::move(aOpenComplete));

View file

@ -21,17 +21,17 @@ class ReadContinuation {
uint32_t aDataSize) = 0;
};
void WriteRecord(cdm::Host_10* aHost, const std::string& aRecordName,
void WriteRecord(cdm::Host_11* aHost, const std::string& aRecordName,
const std::string& aData, std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure);
void WriteRecord(cdm::Host_10* aHost, const std::string& aRecordName,
void WriteRecord(cdm::Host_11* aHost, const std::string& aRecordName,
const uint8_t* aData, uint32_t aNumBytes,
std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure);
void ReadRecord(
cdm::Host_10* aHost, const std::string& aRecordName,
cdm::Host_11* aHost, const std::string& aRecordName,
std::function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete);
class OpenContinuation {
@ -40,6 +40,6 @@ class OpenContinuation {
virtual void operator()(bool aSuccess) = 0;
};
void OpenRecord(cdm::Host_10* aHost, const std::string& aRecordName,
void OpenRecord(cdm::Host_11* aHost, const std::string& aRecordName,
std::function<void(bool)>&& aOpenComplete);
#endif // TEST_CDM_STORAGE_H__

View file

@ -52,6 +52,15 @@ void ChromiumCDMAdapter::SetAdaptee(PRLibrary* aLib) { mLib = aLib; }
void* ChromiumCdmHost(int aHostInterfaceVersion, void* aUserData) {
GMP_LOG_DEBUG("ChromiumCdmHostFunc(%d, %p)", aHostInterfaceVersion,
aUserData);
if (aHostInterfaceVersion != cdm::Host_11::kVersion) {
return nullptr;
}
return aUserData;
}
void* ChromiumCdmHostCompat(int aHostInterfaceVersion, void* aUserData) {
GMP_LOG_DEBUG("ChromiumCdmHostCompatFunc(%d, %p)", aHostInterfaceVersion,
aUserData);
if (aHostInterfaceVersion != cdm::Host_10::kVersion) {
return nullptr;
}
@ -116,16 +125,24 @@ GMPErr ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName, void* aHostAPI,
GMP_LOG_DEBUG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %s) this=0x%p",
aAPIName, aHostAPI, aPluginAPI,
PromiseFlatCString(aKeySystem).get(), this);
bool isCdm10 = !strcmp(aAPIName, CHROMIUM_CDM_API);
if (!isCdm10) {
MOZ_ASSERT_UNREACHABLE("We only support and expect cdm10!");
int version;
GetCdmHostFunc getCdmHostFunc;
if (!strcmp(aAPIName, CHROMIUM_CDM_API)) {
version = cdm::ContentDecryptionModule_11::kVersion;
getCdmHostFunc = &ChromiumCdmHost;
} else if (!strcmp(aAPIName, CHROMIUM_CDM_API_BACKWARD_COMPAT)) {
version = cdm::ContentDecryptionModule_10::kVersion;
getCdmHostFunc = &ChromiumCdmHostCompat;
} else {
MOZ_ASSERT_UNREACHABLE("We only support and expect cdm10/11!");
GMP_LOG_DEBUG(
"ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p got "
"unsupported CDM version!",
aAPIName, aHostAPI, aPluginAPI, this);
return GMPGenericErr;
}
auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
if (!create) {
@ -136,9 +153,8 @@ GMPErr ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName, void* aHostAPI,
return GMPGenericErr;
}
const int version = cdm::ContentDecryptionModule_10::kVersion;
void* cdm = create(version, aKeySystem.BeginReading(), aKeySystem.Length(),
&ChromiumCdmHost, aHostAPI);
getCdmHostFunc, aHostAPI);
if (!cdm) {
GMP_LOG_DEBUG(
"ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p "
@ -169,8 +185,10 @@ bool ChromiumCDMAdapter::Supports(int32_t aModuleVersion,
int32_t aInterfaceVersion,
int32_t aHostVersion) {
return aModuleVersion == CDM_MODULE_VERSION &&
aInterfaceVersion == cdm::ContentDecryptionModule_10::kVersion &&
aHostVersion == cdm::Host_10::kVersion;
((aInterfaceVersion == cdm::ContentDecryptionModule_11::kVersion &&
aHostVersion == cdm::Host_11::kVersion) ||
(aInterfaceVersion == cdm::ContentDecryptionModule_10::kVersion &&
aHostVersion == cdm::Host_10::kVersion));
}
#ifdef XP_WIN

View file

@ -28,7 +28,7 @@ ChromiumCDMChild::ChromiumCDMChild(GMPContentChild* aPlugin)
GMP_LOG_DEBUG("ChromiumCDMChild:: ctor this=%p", this);
}
void ChromiumCDMChild::Init(cdm::ContentDecryptionModule_10* aCDM,
void ChromiumCDMChild::Init(cdm::ContentDecryptionModule_11* aCDM,
const nsACString& aStorageId) {
MOZ_ASSERT(IsOnMessageLoopThread());
mCDM = aCDM;
@ -367,6 +367,13 @@ void ChromiumCDMChild::RequestStorageId(uint32_t aVersion) {
mStorageId.Length());
}
void ChromiumCDMChild::ReportMetrics(cdm::MetricName aMetricName,
uint64_t aValue) {
GMP_LOG_DEBUG("ChromiumCDMChild::ReportMetrics() aMetricName=%" PRIu32
", aValue=%" PRIu64,
aMetricName, aValue);
}
ChromiumCDMChild::~ChromiumCDMChild() {
GMP_LOG_DEBUG("ChromiumCDMChild:: dtor this=%p", this);
}
@ -637,25 +644,32 @@ mozilla::ipc::IPCResult ChromiumCDMChild::RecvDecrypt(
cdm::Status status = mCDM->Decrypt(input, &output);
// CDM should have allocated a cdm::Buffer for output.
CDMShmemBuffer* buffer =
output.DecryptedBuffer()
? static_cast<CDMShmemBuffer*>(output.DecryptedBuffer())
: nullptr;
MOZ_ASSERT_IF(buffer, buffer->AsShmemBuffer());
if (status != cdm::kSuccess || !buffer) {
if (status != cdm::kSuccess || !output.DecryptedBuffer()) {
Unused << SendDecryptFailed(aId, status);
return IPC_OK();
}
// Success! Return the decrypted sample to parent.
MOZ_ASSERT(!HasShmemOfSize(outputShmemSize));
ipc::Shmem shmem = buffer->ExtractShmem();
if (SendDecrypted(aId, cdm::kSuccess, std::move(shmem))) {
// No need to deallocate the output shmem; it should have been returned
// to the content process.
autoDeallocateOutputShmem.release();
auto* buffer = static_cast<CDMBuffer*>(output.DecryptedBuffer());
if (auto* shmemBuffer = buffer->AsShmemBuffer()) {
MOZ_ASSERT(!HasShmemOfSize(outputShmemSize));
ipc::Shmem shmem = shmemBuffer->ExtractShmem();
if (SendDecryptedShmem(aId, cdm::kSuccess, std::move(shmem))) {
// No need to deallocate the output shmem; it should have been returned
// to the content process.
autoDeallocateOutputShmem.release();
}
return IPC_OK();
}
if (auto* arrayBuffer = buffer->AsArrayBuffer()) {
Unused << SendDecryptedData(aId, cdm::kSuccess,
arrayBuffer->ExtractBuffer());
return IPC_OK();
}
MOZ_ASSERT_UNREACHABLE("Unexpected CDMBuffer type!");
GMP_LOG_DEBUG("ChromiumCDMChild::RecvDecrypt() unexpected CDMBuffer type");
Unused << SendDecryptFailed(aId, cdm::kDecryptError);
return IPC_OK();
}
@ -783,12 +797,12 @@ void ChromiumCDMChild::ReturnOutput(WidevineVideoFrame& aFrame) {
output.mFormat() = static_cast<cdm::VideoFormat>(aFrame.Format());
output.mImageWidth() = aFrame.Size().width;
output.mImageHeight() = aFrame.Size().height;
output.mYPlane() = {aFrame.PlaneOffset(cdm::VideoPlane::kYPlane),
aFrame.Stride(cdm::VideoPlane::kYPlane)};
output.mUPlane() = {aFrame.PlaneOffset(cdm::VideoPlane::kUPlane),
aFrame.Stride(cdm::VideoPlane::kUPlane)};
output.mVPlane() = {aFrame.PlaneOffset(cdm::VideoPlane::kVPlane),
aFrame.Stride(cdm::VideoPlane::kVPlane)};
output.mYPlane() = {aFrame.PlaneOffset(cdm::kYPlane),
aFrame.Stride(cdm::kYPlane)};
output.mUPlane() = {aFrame.PlaneOffset(cdm::kUPlane),
aFrame.Stride(cdm::kUPlane)};
output.mVPlane() = {aFrame.PlaneOffset(cdm::kVPlane),
aFrame.Stride(cdm::kVPlane)};
output.mTimestamp() = aFrame.Timestamp();
uint64_t duration = 0;
@ -797,13 +811,18 @@ void ChromiumCDMChild::ReturnOutput(WidevineVideoFrame& aFrame) {
}
CDMBuffer* base = reinterpret_cast<CDMBuffer*>(aFrame.FrameBuffer());
if (base->AsShmemBuffer()) {
ipc::Shmem shmem = base->AsShmemBuffer()->ExtractShmem();
if (auto* shmemBase = base->AsShmemBuffer()) {
ipc::Shmem shmem = shmemBase->ExtractShmem();
Unused << SendDecodedShmem(output, std::move(shmem));
} else {
MOZ_ASSERT(base->AsArrayBuffer());
Unused << SendDecodedData(output, base->AsArrayBuffer()->ExtractBuffer());
return;
}
if (auto* arrayBase = base->AsArrayBuffer()) {
Unused << SendDecodedData(output, arrayBase->ExtractBuffer());
return;
}
MOZ_ASSERT_UNREACHABLE("Unexpected CDMBuffer type!");
}
mozilla::ipc::IPCResult ChromiumCDMChild::RecvDrain() {

View file

@ -15,7 +15,9 @@ namespace mozilla::gmp {
class GMPContentChild;
class ChromiumCDMChild : public PChromiumCDMChild, public cdm::Host_10 {
class ChromiumCDMChild final : public PChromiumCDMChild,
public cdm::Host_10,
public cdm::Host_11 {
public:
// Mark AddRef and Release as `final`, as they overload pure virtual
// implementations in PChromiumCDMChild.
@ -23,12 +25,12 @@ class ChromiumCDMChild : public PChromiumCDMChild, public cdm::Host_10 {
explicit ChromiumCDMChild(GMPContentChild* aPlugin);
void Init(cdm::ContentDecryptionModule_10* aCDM,
void Init(cdm::ContentDecryptionModule_11* aCDM,
const nsACString& aStorageId);
void TimerExpired(void* aContext);
// cdm::Host_10 implementation
// cdm::Host_10/cdm::Host_11 implementation
cdm::Buffer* Allocate(uint32_t aCapacity) override;
void SetTimer(int64_t aDelayMs, void* aContext) override;
cdm::Time GetCurrentWallTime() override;
@ -59,9 +61,10 @@ class ChromiumCDMChild : public PChromiumCDMChild, public cdm::Host_10 {
void OnDeferredInitializationDone(cdm::StreamType aStreamType,
cdm::Status aDecoderStatus) override {}
void RequestStorageId(uint32_t aVersion) override;
void ReportMetrics(cdm::MetricName aMetricName, uint64_t aValue) override;
cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override;
void OnInitialized(bool aSuccess) override;
// end cdm::Host_10 specific methods
// end cdm::Host_10/cdm::Host_11 specific methods
void GiveBuffer(ipc::Shmem&& aBuffer);
@ -123,7 +126,7 @@ class ChromiumCDMChild : public PChromiumCDMChild, public cdm::Host_10 {
void CallOnMessageLoopThread(const char* const, MethodType, ParamType&&...);
GMPContentChild* mPlugin = nullptr;
cdm::ContentDecryptionModule_10* mCDM = nullptr;
cdm::ContentDecryptionModule_11* mCDM = nullptr;
typedef SimpleMap<int64_t, uint64_t, ThreadSafePolicy> DurationMap;
DurationMap mFrameDurations;

View file

@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ChromiumCDMCompat_h_
#define ChromiumCDMCompat_h_
#include "content_decryption_module.h"
namespace mozilla::gmp {
class ChromiumCDMCompat final : public cdm::ContentDecryptionModule_11 {
public:
explicit ChromiumCDMCompat(cdm::ContentDecryptionModule_10* aCDM)
: mCDM(aCDM) {}
void Initialize(bool aAllowDistinctiveIdentifier, bool aAllowPersistentState,
bool aUseHwSecureCodecs) override {
mCDM->Initialize(aAllowDistinctiveIdentifier, aAllowPersistentState,
aUseHwSecureCodecs);
}
void GetStatusForPolicy(uint32_t aPromiseId,
const cdm::Policy& aPolicy) override {
mCDM->GetStatusForPolicy(aPromiseId, aPolicy);
}
void SetServerCertificate(uint32_t aPromiseId,
const uint8_t* aServerCertificateData,
uint32_t aServerCertificateDataSize) override {
mCDM->SetServerCertificate(aPromiseId, aServerCertificateData,
aServerCertificateDataSize);
}
void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
cdm::SessionType aSessionType,
cdm::InitDataType aInitDataType,
const uint8_t* aInitData,
uint32_t aInitDataSize) override {
mCDM->CreateSessionAndGenerateRequest(aPromiseId, aSessionType,
aInitDataType, aInitData, aInitDataSize);
};
void LoadSession(uint32_t aPromiseId, cdm::SessionType aSessionType,
const char* aSessionId, uint32_t aSessionIdSize) override {
mCDM->LoadSession(aPromiseId, aSessionType, aSessionId, aSessionIdSize);
};
void UpdateSession(uint32_t aPromiseId, const char* aSessionId,
uint32_t aSessionIdSize, const uint8_t* aResponse,
uint32_t aResponseSize) override {
mCDM->UpdateSession(aPromiseId, aSessionId, aSessionIdSize, aResponse,
aResponseSize);
};
void CloseSession(uint32_t aPromiseId, const char* aSessionId,
uint32_t aSessionIdSize) override {
mCDM->CloseSession(aPromiseId, aSessionId, aSessionIdSize);
};
void RemoveSession(uint32_t aPromiseId, const char* aSessionId,
uint32_t aSessionIdSize) override {
mCDM->RemoveSession(aPromiseId, aSessionId, aSessionIdSize);
};
void TimerExpired(void* aContext) override { mCDM->TimerExpired(aContext); };
cdm::Status Decrypt(const cdm::InputBuffer_2& aEncryptedBuffer,
cdm::DecryptedBlock* aDecryptedBuffer) override {
return mCDM->Decrypt(aEncryptedBuffer, aDecryptedBuffer);
};
cdm::Status InitializeAudioDecoder(
const cdm::AudioDecoderConfig_2& aAudioDecoderConfig) override {
return mCDM->InitializeAudioDecoder(aAudioDecoderConfig);
};
cdm::Status InitializeVideoDecoder(
const cdm::VideoDecoderConfig_2& aVideoDecoderConfig) override {
return mCDM->InitializeVideoDecoder(aVideoDecoderConfig);
};
void DeinitializeDecoder(cdm::StreamType aDecoderType) override {
mCDM->DeinitializeDecoder(aDecoderType);
};
void ResetDecoder(cdm::StreamType aDecoderType) override {
mCDM->ResetDecoder(aDecoderType);
};
cdm::Status DecryptAndDecodeFrame(const cdm::InputBuffer_2& aEncryptedBuffer,
cdm::VideoFrame* aVideoFrame) override {
return mCDM->DecryptAndDecodeFrame(aEncryptedBuffer, aVideoFrame);
};
cdm::Status DecryptAndDecodeSamples(
const cdm::InputBuffer_2& aEncryptedBuffer,
cdm::AudioFrames* aAudioFrames) override {
return mCDM->DecryptAndDecodeSamples(aEncryptedBuffer, aAudioFrames);
};
void OnPlatformChallengeResponse(
const cdm::PlatformChallengeResponse& aResponse) override {
mCDM->OnPlatformChallengeResponse(aResponse);
};
void OnQueryOutputProtectionStatus(cdm::QueryResult aResult,
uint32_t aLinkMask,
uint32_t aOutputProtectionMask) override {
mCDM->OnQueryOutputProtectionStatus(aResult, aLinkMask,
aOutputProtectionMask);
};
void OnStorageId(uint32_t aVersion, const uint8_t* aStorageId,
uint32_t aStorageIdSize) override {
mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize);
}
// Destroys the object in the same aContext as it was created.
void Destroy() override {
mCDM->Destroy();
delete this;
}
protected:
virtual ~ChromiumCDMCompat() = default;
cdm::ContentDecryptionModule_10* mCDM;
};
} // namespace mozilla::gmp
#endif // ChromiumCDMCompat_h_

View file

@ -686,11 +686,11 @@ ipc::IPCResult ChromiumCDMParent::RecvDecryptFailed(const uint32_t& aId,
return IPC_OK();
}
ipc::IPCResult ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
const uint32_t& aStatus,
ipc::Shmem&& aShmem) {
ipc::IPCResult ChromiumCDMParent::RecvDecryptedShmem(const uint32_t& aId,
const uint32_t& aStatus,
ipc::Shmem&& aShmem) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
GMP_LOG_DEBUG("ChromiumCDMParent::RecvDecrypted(this=%p, id=%" PRIu32
GMP_LOG_DEBUG("ChromiumCDMParent::RecvDecryptedShmem(this=%p, id=%" PRIu32
", status=%" PRIu32 ")",
this, aId, aStatus);
@ -704,9 +704,33 @@ ipc::IPCResult ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
}
for (size_t i = 0; i < mDecrypts.Length(); i++) {
if (mDecrypts[i]->mId == aId) {
mDecrypts[i]->PostResult(
ToDecryptStatus(aStatus),
Span<const uint8_t>(aShmem.get<uint8_t>(), aShmem.Size<uint8_t>()));
mDecrypts[i]->PostResult(ToDecryptStatus(aStatus),
aShmem.IsReadable()
? Span<const uint8_t>(aShmem.get<uint8_t>(),
aShmem.Size<uint8_t>())
: Span<const uint8_t>());
mDecrypts.RemoveElementAt(i);
break;
}
}
return IPC_OK();
}
ipc::IPCResult ChromiumCDMParent::RecvDecryptedData(const uint32_t& aId,
const uint32_t& aStatus,
nsTArray<uint8_t>&& aData) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
GMP_LOG_DEBUG("ChromiumCDMParent::RecvDecryptedData(this=%p, id=%" PRIu32
", status=%" PRIu32 ")",
this, aId, aStatus);
if (mIsShutdown) {
MOZ_ASSERT(mDecrypts.IsEmpty());
return IPC_OK();
}
for (size_t i = 0; i < mDecrypts.Length(); i++) {
if (mDecrypts[i]->mId == aId) {
mDecrypts[i]->PostResult(ToDecryptStatus(aStatus), aData);
mDecrypts.RemoveElementAt(i);
break;
}

View file

@ -126,8 +126,11 @@ class ChromiumCDMParent final : public PChromiumCDMParent,
const double& aSecondsSinceEpoch);
ipc::IPCResult RecvOnSessionClosed(const nsCString& aSessionId);
ipc::IPCResult RecvOnQueryOutputProtectionStatus();
ipc::IPCResult RecvDecrypted(const uint32_t& aId, const uint32_t& aStatus,
ipc::Shmem&& aData);
ipc::IPCResult RecvDecryptedShmem(const uint32_t& aId,
const uint32_t& aStatus,
ipc::Shmem&& aData);
ipc::IPCResult RecvDecryptedData(const uint32_t& aId, const uint32_t& aStatus,
nsTArray<uint8_t>&& aData);
ipc::IPCResult RecvDecryptFailed(const uint32_t& aId,
const uint32_t& aStatus);
ipc::IPCResult RecvOnDecoderInitDone(const uint32_t& aStatus);

View file

@ -27,11 +27,13 @@ void DecryptJob::PostResult(DecryptStatus aResult,
if (aDecryptedData.Length() != mSample->Size()) {
NS_WARNING("CDM returned incorrect number of decrypted bytes");
}
if (aResult == eme::Ok) {
if (aResult == DecryptStatus::Ok) {
UniquePtr<MediaRawDataWriter> writer(mSample->CreateWriter());
PodCopy(writer->Data(), aDecryptedData.Elements(),
std::min<size_t>(aDecryptedData.Length(), mSample->Size()));
} else if (aResult == eme::NoKeyErr) {
if (NS_WARN_IF(!writer->Replace(aDecryptedData.Elements(),
aDecryptedData.Length()))) {
aResult = DecryptStatus::GenericErr;
}
} else if (aResult == DecryptStatus::NoKeyErr) {
NS_WARNING("CDM returned NoKeyErr");
// We still have the encrypted sample, so we can re-enqueue it to be
// decrypted again once the key is usable again.

View file

@ -8,6 +8,7 @@
#include "GMPVideoDecoderChild.h"
#include "GMPVideoEncoderChild.h"
#include "ChromiumCDMChild.h"
#include "ChromiumCDMCompat.h"
#include "base/task.h"
#include "GMPUtils.h"
@ -88,15 +89,23 @@ mozilla::ipc::IPCResult GMPContentChild::RecvPGMPVideoEncoderConstructor(
mozilla::ipc::IPCResult GMPContentChild::RecvPChromiumCDMConstructor(
PChromiumCDMChild* aActor, const nsACString& aKeySystem) {
ChromiumCDMChild* child = static_cast<ChromiumCDMChild*>(aActor);
cdm::Host_10* host10 = child;
void* cdm = nullptr;
GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API, host10, &cdm, aKeySystem);
GMPErr err = mGMPChild->GetAPI(
CHROMIUM_CDM_API, static_cast<cdm::Host_11*>(child), &cdm, aKeySystem);
if (err != GMPNoErr || !cdm) {
return IPC_FAIL(this, "GMPGetAPI call failed trying to get CDM.");
err =
mGMPChild->GetAPI(CHROMIUM_CDM_API_BACKWARD_COMPAT,
static_cast<cdm::Host_10*>(child), &cdm, aKeySystem);
if (err != GMPNoErr || !cdm) {
return IPC_FAIL(this, "GMPGetAPI call failed trying to get CDM.");
}
cdm = new ChromiumCDMCompat(
static_cast<cdm::ContentDecryptionModule_10*>(cdm));
}
child->Init(static_cast<cdm::ContentDecryptionModule_10*>(cdm),
child->Init(static_cast<cdm::ContentDecryptionModule_11*>(cdm),
mGMPChild->mStorageId);
return IPC_OK();

View file

@ -16,8 +16,8 @@
#include "nsStringFwd.h"
#include "nsTArray.h"
#define CHROMIUM_CDM_API_BACKWARD_COMPAT "chromium-cdm9-host4"
#define CHROMIUM_CDM_API "chromium-cdm10-host4"
#define CHROMIUM_CDM_API_BACKWARD_COMPAT "chromium-cdm10-host4"
#define CHROMIUM_CDM_API "chromium-cdm11-host4"
class GMPVideoEncodedFrame;
class nsIFile;

View file

@ -77,7 +77,7 @@ child:
parent:
async __delete__();
// cdm::Host_10
// cdm::Host_11
async OnResolvePromiseWithKeyStatus(uint32_t aPromiseId, uint32_t aKeyStatus);
async OnResolveNewSessionPromise(uint32_t aPromiseId, nsCString aSessionId);
@ -106,7 +106,8 @@ parent:
async ResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccessful);
// Return values of cdm::ContentDecryptionModule_10::Decrypt
async Decrypted(uint32_t aId, uint32_t aStatus, Shmem aDecryptedData);
async DecryptedShmem(uint32_t aId, uint32_t aStatus, Shmem aData);
async DecryptedData(uint32_t aId, uint32_t aStatus, uint8_t[] aData);
async DecryptFailed(uint32_t aId, uint32_t aStatus);
async OnDecoderInitDone(uint32_t aStatus);

View file

@ -62,10 +62,6 @@ EXPORTS += [
"GMPVideoHost.h",
"GMPVideoi420FrameImpl.h",
"GMPVideoPlaneImpl.h",
"widevine-adapter/content_decryption_module.h",
"widevine-adapter/content_decryption_module_export.h",
"widevine-adapter/content_decryption_module_ext.h",
"widevine-adapter/content_decryption_module_proxy.h",
]
UNIFIED_SOURCES += [

View file

@ -127,14 +127,14 @@ bool WidevineVideoFrame::InitToBlack(int32_t aWidth, int32_t aHeight,
SetFormat(cdm::VideoFormat::kI420);
SetSize(cdm::Size{aWidth, aHeight});
SetFrameBuffer(buffer);
SetPlaneOffset(cdm::VideoPlane::kYPlane, 0);
SetStride(cdm::VideoPlane::kYPlane, aWidth);
SetPlaneOffset(cdm::kYPlane, 0);
SetStride(cdm::kYPlane, aWidth);
// Note: U and V planes are stored at the same place in order to
// save memory since their contents are the same.
SetPlaneOffset(cdm::VideoPlane::kUPlane, ySize);
SetStride(cdm::VideoPlane::kUPlane, halfWidth);
SetPlaneOffset(cdm::VideoPlane::kVPlane, ySize);
SetStride(cdm::VideoPlane::kVPlane, halfWidth);
SetPlaneOffset(cdm::kUPlane, ySize);
SetStride(cdm::kUPlane, halfWidth);
SetPlaneOffset(cdm::kVPlane, ySize);
SetStride(cdm::kVPlane, halfWidth);
SetTimestamp(aTimeStamp);
return true;
}

View file

@ -44,8 +44,8 @@ class WidevineVideoFrame : public cdm::VideoFrame {
cdm::VideoFormat mFormat;
cdm::Size mSize;
cdm::Buffer* mBuffer;
uint32_t mPlaneOffsets[cdm::VideoPlane::kMaxPlanes];
uint32_t mPlaneStrides[cdm::VideoPlane::kMaxPlanes];
uint32_t mPlaneOffsets[cdm::kMaxPlanes];
uint32_t mPlaneStrides[cdm::kMaxPlanes];
int64_t mTimestamp;
};

View file

@ -8,7 +8,6 @@
#include <type_traits>
#include "content_decryption_module_export.h"
#include "content_decryption_module_proxy.h"
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
@ -16,7 +15,7 @@ typedef unsigned int uint32_t;
typedef int int32_t;
typedef __int64 int64_t;
#else
# include <stdint.h>
#include <stdint.h>
#endif
// The version number must be rolled when the exported functions are updated!
@ -411,6 +410,7 @@ CHECK_TYPE(InitDataType, 4, 4);
enum SessionType : uint32_t {
kTemporary = 0,
kPersistentLicense = 1,
kPersistentUsageRecord = 2
};
CHECK_TYPE(SessionType, 4, 4);
@ -479,12 +479,13 @@ class CDM_CLASS_API DecryptedBlock {
virtual ~DecryptedBlock() {}
};
enum VideoPlane : uint32_t {
kYPlane = 0,
kUPlane = 1,
kVPlane = 2,
kMaxPlanes = 3,
};
// This intentionally avoids using an enum, since it will be used to do math
// with other enums, which is deprecated in C++20.
using VideoPlane = uint32_t;
constexpr VideoPlane kYPlane = 0;
constexpr VideoPlane kUPlane = 1;
constexpr VideoPlane kVPlane = 2;
constexpr VideoPlane kMaxPlanes = 3;
CHECK_TYPE(VideoPlane, 4, 4);
class CDM_CLASS_API VideoFrame {
@ -622,7 +623,8 @@ class CDM_CLASS_API FileIOClient {
// - kInUse indicates that there are other read/write operations pending.
// - kError indicates read failure, e.g. the storage is not open or cannot be
// fully read.
virtual void OnReadComplete(Status status, const uint8_t* data,
virtual void OnReadComplete(Status status,
const uint8_t* data,
uint32_t data_size) = 0;
// Response to a FileIO::Write() call.
@ -639,8 +641,21 @@ class CDM_CLASS_API FileIOClient {
virtual ~FileIOClient() {}
};
// Metrics that will be reported from the CDM through the ReportMetrics()
// function. To add a new metric, please add it to the end of this enum list
// without changing any existing enum values.
// Note: For forward compatibility, Host implementations must gracefully handle
// unexpected (new) enum values, e.g. no-op.
enum MetricName : uint32_t {
kSdkVersion,
kCertificateSerialNumber,
kDecoderBypassBlockCount,
};
CHECK_TYPE(MetricName, 4, 4);
class CDM_CLASS_API Host_10;
class CDM_CLASS_API Host_11;
class CDM_CLASS_API Host_12;
// ContentDecryptionModule interface that all CDMs need to implement.
// The interface is versioned for backward compatibility.
@ -708,28 +723,33 @@ class CDM_CLASS_API ContentDecryptionModule_10 {
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise(). If the session is not found, call
// Host::OnResolveNewSessionPromise() with session_id = NULL.
virtual void LoadSession(uint32_t promise_id, SessionType session_type,
virtual void LoadSession(uint32_t promise_id,
SessionType session_type,
const char* session_id,
uint32_t session_id_size) = 0;
// Updates the session with |response|. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void UpdateSession(uint32_t promise_id, const char* session_id,
uint32_t session_id_size, const uint8_t* response,
virtual void UpdateSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
// Requests that the CDM close the session. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
// has been processed. This may be before the session is closed. Once the
// session is closed, Host::OnSessionClosed() must also be called.
virtual void CloseSession(uint32_t promise_id, const char* session_id,
virtual void CloseSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Removes any stored session data associated with this session. Will only be
// called for persistent sessions. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
// been processed.
virtual void RemoveSession(uint32_t promise_id, const char* session_id,
virtual void RemoveSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Performs scheduled operation with |context| when the timer fires.
@ -833,7 +853,8 @@ class CDM_CLASS_API ContentDecryptionModule_10 {
// then |link_mask| and |output_protection_mask| are undefined and should
// be ignored.
virtual void OnQueryOutputProtectionStatus(
QueryResult result, uint32_t link_mask,
QueryResult result,
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
// Called by the host after a call to Host::RequestStorageId(). If the
@ -844,7 +865,8 @@ class CDM_CLASS_API ContentDecryptionModule_10 {
// 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,
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.
@ -855,8 +877,6 @@ class CDM_CLASS_API ContentDecryptionModule_10 {
virtual ~ContentDecryptionModule_10() {}
};
// ----- Note: CDM interface(s) below still in development and not stable! -----
// ContentDecryptionModule interface that all CDMs need to implement.
// The interface is versioned for backward compatibility.
// Note: ContentDecryptionModule implementations must use the allocator
@ -866,7 +886,7 @@ class CDM_CLASS_API ContentDecryptionModule_10 {
class CDM_CLASS_API ContentDecryptionModule_11 {
public:
static const int kVersion = 11;
static const bool kIsStable = false;
static const bool kIsStable = true;
typedef Host_11 Host;
// Initializes the CDM instance, providing information about permitted
@ -923,21 +943,247 @@ class CDM_CLASS_API ContentDecryptionModule_11 {
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise(). If the session is not found, call
// Host::OnResolveNewSessionPromise() with session_id = NULL.
virtual void LoadSession(uint32_t promise_id, SessionType session_type,
virtual void LoadSession(uint32_t promise_id,
SessionType session_type,
const char* session_id,
uint32_t session_id_size) = 0;
// Updates the session with |response|. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void UpdateSession(uint32_t promise_id, const char* session_id,
uint32_t session_id_size, const uint8_t* response,
virtual void UpdateSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
// Requests that the CDM close the session. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
// has been processed. This may be before the session is closed. Once the
// session is closed, Host::OnSessionClosed() must also be called.
virtual void CloseSession(uint32_t promise_id, const char* session_id,
virtual void CloseSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Removes any stored session data associated with this session. Will only be
// called for persistent sessions. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
// been processed.
virtual void RemoveSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Performs scheduled operation with |context| when the timer fires.
virtual void TimerExpired(void* context) = 0;
// Decrypts the |encrypted_buffer|.
//
// Returns kSuccess if decryption succeeded, in which case the callee
// should have filled the |decrypted_buffer| and passed the ownership of
// |data| in |decrypted_buffer| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kDecryptError if any other error happened.
// If the return value is not kSuccess, |decrypted_buffer| should be ignored
// by the caller.
virtual Status Decrypt(const InputBuffer_2& encrypted_buffer,
DecryptedBlock* decrypted_buffer) = 0;
// Initializes the CDM audio decoder with |audio_decoder_config|. This
// function must be called before DecryptAndDecodeSamples() is called.
//
// Returns kSuccess if the |audio_decoder_config| is supported and the CDM
// audio decoder is successfully initialized.
// 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.
virtual Status InitializeAudioDecoder(
const AudioDecoderConfig_2& audio_decoder_config) = 0;
// Initializes the CDM video decoder with |video_decoder_config|. This
// function must be called before DecryptAndDecodeFrame() is called.
//
// Returns kSuccess if the |video_decoder_config| is supported and the CDM
// video decoder is successfully initialized.
// 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.
virtual Status InitializeVideoDecoder(
const VideoDecoderConfig_2& video_decoder_config) = 0;
// De-initializes the CDM decoder and sets it to an uninitialized state. The
// caller can initialize the decoder again after this call to re-initialize
// it. This can be used to reconfigure the decoder if the configuration
// changes.
virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
// Resets the CDM decoder to an initialized clean state. All internal buffers
// MUST be flushed.
virtual void ResetDecoder(StreamType decoder_type) = 0;
// Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
// |video_frame|. Upon end-of-stream, the caller should call this function
// repeatedly with empty |encrypted_buffer| (|data| == NULL) until
// kNeedMoreData is returned.
//
// Returns kSuccess if decryption and decoding both succeeded, in which case
// the callee will have filled the |video_frame| and passed the ownership of
// |frame_buffer| in |video_frame| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kNeedMoreData if more data was needed by the decoder to generate
// a decoded frame (e.g. during initialization and end-of-stream).
// Returns kDecryptError if any decryption error happened.
// Returns kDecodeError if any decoding error happened.
// If the return value is not kSuccess, |video_frame| should be ignored by
// the caller.
virtual Status DecryptAndDecodeFrame(const InputBuffer_2& encrypted_buffer,
VideoFrame* video_frame) = 0;
// Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
// |audio_frames|. Upon end-of-stream, the caller should call this function
// repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
// |audio_frames| is produced.
//
// Returns kSuccess if decryption and decoding both succeeded, in which case
// the callee will have filled |audio_frames| and passed the ownership of
// |data| in |audio_frames| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kNeedMoreData if more data was needed by the decoder to generate
// audio samples (e.g. during initialization and end-of-stream).
// Returns kDecryptError if any decryption error happened.
// Returns kDecodeError if any decoding error happened.
// If the return value is not kSuccess, |audio_frames| should be ignored by
// the caller.
virtual Status DecryptAndDecodeSamples(const InputBuffer_2& encrypted_buffer,
AudioFrames* audio_frames) = 0;
// Called by the host after a platform challenge was initiated via
// Host::SendPlatformChallenge().
virtual void OnPlatformChallengeResponse(
const PlatformChallengeResponse& response) = 0;
// Called by the host after a call to Host::QueryOutputProtectionStatus(). The
// |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
// is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
// then |link_mask| and |output_protection_mask| are undefined and should
// be ignored.
virtual void OnQueryOutputProtectionStatus(
QueryResult result,
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_11() {}
virtual ~ContentDecryptionModule_11() {}
};
// ----- Note: CDM interface(s) below still in development and not stable! -----
// ContentDecryptionModule interface that all CDMs need to implement.
// The interface is versioned for backward compatibility.
// Note: ContentDecryptionModule implementations must use the allocator
// 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 CDM_CLASS_API ContentDecryptionModule_12 {
public:
static const int kVersion = 12;
static const bool kIsStable = false;
typedef Host_12 Host;
// Initializes the CDM instance, providing information about permitted
// functionalities. The CDM must respond by calling Host::OnInitialized()
// with whether the initialization succeeded. No other calls will be made by
// the host before Host::OnInitialized() returns.
// 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.
// If |use_hw_secure_codecs| is true, the CDM must ensure the decryption key
// and video buffers (compressed and uncompressed) are securely protected by
// hardware.
virtual void Initialize(bool allow_distinctive_identifier,
bool allow_persistent_state,
bool use_hw_secure_codecs) = 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
// (e.g. Host::OnResolveNewSessionPromise()).
// Provides a server certificate to be used to encrypt messages to the
// license server. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise().
// If the CDM does not support server certificates, the promise should be
// rejected with kExceptionNotSupportedError. If |server_certificate_data|
// is empty, reject with kExceptionTypeError. Any other error should be
// rejected with kExceptionInvalidStateError or kExceptionQuotaExceededError.
// TODO(crbug.com/796417): Add support for the promise to return true or
// false, rather than using kExceptionNotSupportedError to mean false.
virtual void SetServerCertificate(uint32_t promise_id,
const uint8_t* server_certificate_data,
uint32_t server_certificate_data_size) = 0;
// Creates a session given |session_type|, |init_data_type|, and |init_data|.
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise().
virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
SessionType session_type,
InitDataType init_data_type,
const uint8_t* init_data,
uint32_t init_data_size) = 0;
// Loads the session of type |session_type| specified by |session_id|.
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise(). If the session is not found, call
// Host::OnResolveNewSessionPromise() with session_id = NULL.
virtual void LoadSession(uint32_t promise_id,
SessionType session_type,
const char* session_id,
uint32_t session_id_size) = 0;
// Updates the session with |response|. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void UpdateSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
// Requests that the CDM close the session. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
// has been processed. This may be before the session is closed. Once the
// session is closed, Host::OnSessionClosed() must also be called.
virtual void CloseSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Removes any stored session data associated with this session. Removes all
@ -948,7 +1194,8 @@ class CDM_CLASS_API ContentDecryptionModule_11 {
// processed by UpdateSession(). The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
// been processed.
virtual void RemoveSession(uint32_t promise_id, const char* session_id,
virtual void RemoveSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Performs scheduled operation with |context| when the timer fires.
@ -1052,7 +1299,8 @@ class CDM_CLASS_API ContentDecryptionModule_11 {
// then |link_mask| and |output_protection_mask| are undefined and should
// be ignored.
virtual void OnQueryOutputProtectionStatus(
QueryResult result, uint32_t link_mask,
QueryResult result,
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
// Called by the host after a call to Host::RequestStorageId(). If the
@ -1063,15 +1311,16 @@ class CDM_CLASS_API ContentDecryptionModule_11 {
// 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,
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_11() {}
virtual ~ContentDecryptionModule_11() {}
ContentDecryptionModule_12() {}
virtual ~ContentDecryptionModule_12() {}
};
class CDM_CLASS_API Host_10 {
@ -1118,15 +1367,18 @@ class CDM_CLASS_API Host_10 {
// ContentDecryptionModule calls that accept a |promise_id|.
// |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, Exception exception,
uint32_t system_code, const char* error_message,
virtual void OnRejectPromise(uint32_t promise_id,
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.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type, const char* message,
MessageType message_type,
const char* message,
uint32_t message_size) = 0;
// Called by the CDM when there has been a change in keys or their status for
@ -1251,15 +1503,18 @@ class CDM_CLASS_API Host_11 {
// ContentDecryptionModule calls that accept a |promise_id|.
// |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, Exception exception,
uint32_t system_code, const char* error_message,
virtual void OnRejectPromise(uint32_t promise_id,
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.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type, const char* message,
MessageType message_type,
const char* message,
uint32_t message_size) = 0;
// Called by the CDM when there has been a change in keys or their status for
@ -1326,18 +1581,146 @@ class CDM_CLASS_API Host_11 {
// CDM can call this method multiple times to operate on different files.
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
// Requests a CdmProxy that proxies part of CDM functionalities to a different
// entity, e.g. a hardware CDM module. A CDM instance can have at most one
// CdmProxy throughout its lifetime, which must be requested and initialized
// during CDM instance initialization time, i.e. in or after CDM::Initialize()
// and before OnInitialized() is called, to ensure proper connection of the
// CdmProxy and the media player (e.g. hardware decoder). The CdmProxy is
// owned by the host and is guaranteed to be valid throughout the CDM
// instance's lifetime. The CDM must ensure that the |client| remain valid
// before the CDM instance is destroyed. Returns null if CdmProxy is not
// supported, called before CDM::Initialize(), RequestCdmProxy() is called
// more than once, or called after the CDM instance has been initialized.
virtual CdmProxy* RequestCdmProxy(CdmProxyClient* 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;
// Reports the metric |metric_name| with value |value| to the host. Can be
// called by the CDM at any time. May report the same metric multiple times
// during the lifetime of the CDM.
virtual void ReportMetrics(MetricName metric_name, uint64_t value) = 0;
protected:
Host_11() {}
virtual ~Host_11() {}
};
class CDM_CLASS_API Host_12 {
public:
static const int kVersion = 12;
// 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
// guaranteed to be zero initialized. The capacity of the allocated Buffer
// is guaranteed to be not less than |capacity|.
virtual Buffer* Allocate(uint32_t capacity) = 0;
// Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
// Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
// Called by the CDM with the result after the CDM instance was initialized.
virtual void OnInitialized(bool success) = 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
// OnSessionKeysChange() is called for the same session. |session_id_size|
// should not include null termination.
// When called in response to LoadSession(), the |session_id| must be the
// same as the |session_id| passed in LoadSession(), or NULL if the
// session could not be loaded.
virtual void OnResolveNewSessionPromise(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Called by the CDM when a session is updated or released.
virtual void OnResolvePromise(uint32_t promise_id) = 0;
// Called by the CDM when an error occurs as a result of one of the
// ContentDecryptionModule calls that accept a |promise_id|.
// |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,
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.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type,
const char* message,
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
// key is newly usable (e.g. new key available, previously expired key has
// been renewed, etc.) and the browser should attempt to resume playback.
// |keys_info| is the list of key IDs for this session along with their
// current status. |keys_info_count| is the number of entries in |keys_info|.
// Size parameter for |session_id| should not include null termination.
virtual void OnSessionKeysChange(const char* session_id,
uint32_t session_id_size,
bool has_additional_usable_key,
const KeyInformation* keys_info,
uint32_t keys_info_count) = 0;
// Called by the CDM when there has been a change in the expiration time for
// 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|
// 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;
// Called by the CDM when session |session_id| is closed. Size
// parameter should not include null termination.
virtual void OnSessionClosed(const char* session_id,
uint32_t session_id_size) = 0;
// The following are optional methods that may not be implemented on all
// platforms.
// Sends a platform challenge for the given |service_id|. |challenge| is at
// most 256 bits of data to be signed. Once the challenge has been completed,
// the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
// with the signed challenge response and platform certificate. Size
// parameters should not include null termination.
virtual void SendPlatformChallenge(const char* service_id,
uint32_t service_id_size,
const char* challenge,
uint32_t challenge_size) = 0;
// Attempts to enable output protection (e.g. HDCP) on the display link. The
// |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
// status callback is issued, the CDM must call QueryOutputProtectionStatus()
// periodically to ensure the desired protections are applied.
virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
// Requests the current output protection status. Once the host has the status
// it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
virtual void QueryOutputProtectionStatus() = 0;
// Must be called by the CDM if it returned kDeferredInitialization during
// InitializeAudioDecoder() or InitializeVideoDecoder().
virtual void OnDeferredInitializationDone(StreamType stream_type,
Status decoder_status) = 0;
// Creates a FileIO object from the host to do file IO operation. Returns NULL
// if a FileIO object cannot be obtained. Once a valid FileIO object is
// returned, |client| must be valid until FileIO::Close() is called. The
// 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
@ -1348,9 +1731,14 @@ class CDM_CLASS_API Host_11 {
// the ID outside the client device, even in encrypted form.
virtual void RequestStorageId(uint32_t version) = 0;
// Reports the metric |metric_name| with value |value| to the host. Can be
// called by the CDM at any time. May report the same metric multiple times
// during the lifetime of the CDM.
virtual void ReportMetrics(MetricName metric_name, uint64_t value) = 0;
protected:
Host_11() {}
virtual ~Host_11() {}
Host_12() {}
virtual ~Host_12() {}
};
} // namespace cdm

View file

@ -1,121 +0,0 @@
// 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_PROXY_H_
#define CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
#include "content_decryption_module_export.h"
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#endif
namespace cdm {
class CDM_CLASS_API CdmProxyClient;
// A proxy class for the CDM.
// In general, the interpretation of the CdmProxy and CdmProxyClient method
// parameters are protocol dependent. For enum parameters, values outside the
// enum range may not work.
class CDM_CLASS_API CdmProxy {
public:
enum Function : uint32_t {
// For Intel Negotiate Crypto SessionKey Exchange (CSME) path to call
// ID3D11VideoContext::NegotiateCryptoSessionKeyExchange.
kIntelNegotiateCryptoSessionKeyExchange = 1,
// There will be more values in the future e.g. for D3D11 RSA method.
};
enum KeyType : uint32_t {
kDecryptOnly = 0,
kDecryptAndDecode = 1,
};
// Initializes the proxy. The results will be returned in
// CdmProxyClient::OnInitialized().
virtual void Initialize() = 0;
// Processes and updates the state of the proxy.
// |output_data_size| is required by some protocol to set up the output data.
// The operation may fail if the |output_data_size| is wrong. The results will
// be returned in CdmProxyClient::OnProcessed().
virtual void Process(Function function, uint32_t crypto_session_id,
const uint8_t* input_data, uint32_t input_data_size,
uint32_t output_data_size) = 0;
// Creates a crypto session for handling media.
// If extra data has to be passed to further setup the media crypto session,
// pass the data as |input_data|. The results will be returned in
// CdmProxyClient::OnMediaCryptoSessionCreated().
virtual void CreateMediaCryptoSession(const uint8_t* input_data,
uint32_t input_data_size) = 0;
// Sets a key for the session identified by |crypto_session_id|.
virtual void SetKey(uint32_t crypto_session_id, const uint8_t* key_id,
uint32_t key_id_size, KeyType key_type,
const uint8_t* key_blob, uint32_t key_blob_size) = 0;
// Removes a key for the session identified by |crypto_session_id|.
virtual void RemoveKey(uint32_t crypto_session_id, const uint8_t* key_id,
uint32_t key_id_size) = 0;
protected:
CdmProxy() {}
virtual ~CdmProxy() {}
};
// Responses to CdmProxy calls. All responses will be called asynchronously.
class CDM_CLASS_API CdmProxyClient {
public:
enum Status : uint32_t {
kOk,
kFail,
};
enum Protocol : uint32_t {
kNone = 0, // No protocol supported. Can be used in failure cases.
kIntel, // Method using Intel CSME.
// There will be more values in the future e.g. kD3D11RsaHardware,
// kD3D11RsaSoftware to use the D3D11 RSA method.
};
// Callback for Initialize(). If the proxy created a crypto session, then the
// ID for the crypto session is |crypto_session_id|.
virtual void OnInitialized(Status status, Protocol protocol,
uint32_t crypto_session_id) = 0;
// Callback for Process(). |output_data| is the output of processing.
virtual void OnProcessed(Status status, const uint8_t* output_data,
uint32_t output_data_size) = 0;
// Callback for CreateMediaCryptoSession(). On success:
// - |crypto_session_id| is the ID for the created crypto session.
// - |output_data| is extra value, if any.
// Otherwise, |crypto_session_id| and |output_data| should be ignored.
virtual void OnMediaCryptoSessionCreated(Status status,
uint32_t crypto_session_id,
uint64_t output_data) = 0;
// Callback for SetKey().
virtual void OnKeySet(Status status) = 0;
// Callback for RemoveKey().
virtual void OnKeyRemoved(Status status) = 0;
// Called when there is a hardware reset and all the hardware context is lost.
virtual void NotifyHardwareReset() = 0;
protected:
CdmProxyClient() {}
virtual ~CdmProxyClient() {}
};
} // namespace cdm
#endif // CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_

View file

@ -10,7 +10,14 @@ SOURCES += [
"WidevineVideoFrame.cpp",
]
EXPORTS += ["WidevineFileIO.h", "WidevineUtils.h", "WidevineVideoFrame.h"]
EXPORTS += [
"content_decryption_module.h",
"content_decryption_module_export.h",
"content_decryption_module_ext.h",
"WidevineFileIO.h",
"WidevineUtils.h",
"WidevineVideoFrame.h",
]
FINAL_LIBRARY = "xul"

View file

@ -16,24 +16,36 @@ namespace mozilla::dom {
// https://streams.spec.whatwg.org/#transfer-array-buffer
// As some parts of the specifcation want to use the abrupt completion value,
// this function may leave a pending exception if it returns nullptr.
//
// This can be called with a CCW to an ArrayBuffer Object as we handle the
// case explicitly.
JSObject* TransferArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aObject) {
MOZ_ASSERT(JS::IsArrayBufferObject(aObject));
// Step 1.
MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(aObject));
// Step 3 (Reordered)
size_t bufferLength = JS::GetArrayBufferByteLength(aObject);
// Step 2 (Reordered)
UniquePtr<void, JS::FreePolicy> bufferData{
JS::StealArrayBufferContents(aCx, aObject)};
// Step 4.
if (!JS::DetachArrayBuffer(aCx, aObject)) {
JS::Rooted<JSObject*> unwrappedObj(aCx, JS::UnwrapArrayBuffer(aObject));
if (!unwrappedObj) {
js::ReportAccessDenied(aCx);
return nullptr;
}
size_t bufferLength = 0;
UniquePtr<void, JS::FreePolicy> bufferData;
{
JSAutoRealm ar(aCx, unwrappedObj);
// Step 1.
MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(unwrappedObj));
// Step 3 (Reordered)
bufferLength = JS::GetArrayBufferByteLength(unwrappedObj);
// Step 2 (Reordered)
bufferData.reset(JS::StealArrayBufferContents(aCx, unwrappedObj));
// Step 4.
if (!JS::DetachArrayBuffer(aCx, unwrappedObj)) {
return nullptr;
}
}
// Step 5.
return JS::NewArrayBufferWithContents(aCx, bufferLength,
std::move(bufferData));