From 07fd8cebf7176b3003b5e2d2921e80d12338e034 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 13 Jan 2017 13:23:31 -0800 Subject: [PATCH] Backed out 3 changesets (bug 1318965) for frequent media test failures a=backout Backed out changeset 3f756d8ee4cf (bug 1318965) Backed out changeset 4bdf65d60c9e (bug 1318965) Backed out changeset c1e2b6c14a7f (bug 1318965) MozReview-Commit-ID: 6CPk5oS5AOw --HG-- extra : source : babe3f8a0258fb592e17a590450de6ceb09460c3 --- dom/media/gmp/moz.build | 3 +- .../widevine-adapter/WidevineDecryptor.cpp | 11 - media/gmp-clearkey/0.1/AnnexB.cpp | 79 + media/gmp-clearkey/0.1/AnnexB.h | 32 + .../0.1/ClearKeyAsyncShutdown.cpp | 45 + .../gmp-clearkey/0.1/ClearKeyAsyncShutdown.h | 37 + media/gmp-clearkey/0.1/ClearKeyCDM.cpp | 195 -- media/gmp-clearkey/0.1/ClearKeyCDM.h | 98 - .../0.1/ClearKeyDecryptionManager.cpp | 59 +- .../0.1/ClearKeyDecryptionManager.h | 47 +- .../gmp-clearkey/0.1/ClearKeyPersistence.cpp | 300 ++- media/gmp-clearkey/0.1/ClearKeyPersistence.h | 54 +- media/gmp-clearkey/0.1/ClearKeySession.cpp | 44 +- media/gmp-clearkey/0.1/ClearKeySession.h | 23 +- .../0.1/ClearKeySessionManager.cpp | 542 ++--- .../gmp-clearkey/0.1/ClearKeySessionManager.h | 126 +- media/gmp-clearkey/0.1/ClearKeyStorage.cpp | 232 +- media/gmp-clearkey/0.1/ClearKeyStorage.h | 37 +- media/gmp-clearkey/0.1/ClearKeyUtils.cpp | 99 +- media/gmp-clearkey/0.1/ClearKeyUtils.h | 48 +- media/gmp-clearkey/0.1/RefCounted.h | 64 +- media/gmp-clearkey/0.1/VideoDecoder.cpp | 463 ++-- media/gmp-clearkey/0.1/VideoDecoder.h | 74 +- media/gmp-clearkey/0.1/WMFH264Decoder.cpp | 8 +- media/gmp-clearkey/0.1/WMFH264Decoder.h | 4 +- media/gmp-clearkey/0.1/WMFUtils.h | 4 +- media/gmp-clearkey/0.1/gmp-clearkey.cpp | 79 +- .../0.1/gmp-task-utils-generated.h | 1938 +++++++++++++++++ media/gmp-clearkey/0.1/gmp-task-utils.h | 47 + media/gmp-clearkey/0.1/moz.build | 11 +- 30 files changed, 3318 insertions(+), 1485 deletions(-) create mode 100644 media/gmp-clearkey/0.1/AnnexB.cpp create mode 100644 media/gmp-clearkey/0.1/AnnexB.h create mode 100644 media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp create mode 100644 media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h delete mode 100644 media/gmp-clearkey/0.1/ClearKeyCDM.cpp delete mode 100644 media/gmp-clearkey/0.1/ClearKeyCDM.h create mode 100644 media/gmp-clearkey/0.1/gmp-task-utils-generated.h create mode 100644 media/gmp-clearkey/0.1/gmp-task-utils.h diff --git a/dom/media/gmp/moz.build b/dom/media/gmp/moz.build index 3ff19ba528bb..aa4354f05573 100644 --- a/dom/media/gmp/moz.build +++ b/dom/media/gmp/moz.build @@ -72,7 +72,6 @@ EXPORTS += [ 'GMPVideoHost.h', 'GMPVideoi420FrameImpl.h', 'GMPVideoPlaneImpl.h', - 'widevine-adapter/content_decryption_module.h', ] # We link GMPLoader into xul on Android and Linux as its code does not @@ -120,7 +119,7 @@ UNIFIED_SOURCES += [ 'GMPVideoEncoderParent.cpp', 'GMPVideoHost.cpp', 'GMPVideoi420FrameImpl.cpp', - 'GMPVideoPlaneImpl.cpp' + 'GMPVideoPlaneImpl.cpp', ] DIRS += [ diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index 683697b87608..e7b56730a6f2 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -313,17 +313,6 @@ WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId, Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId); return; } - - // This is laid out in the API. If we fail to load a session we should - // call OnResolveNewSessionPromise with nullptr as the sessionId. - // We can safely assume this means that we have failed to load a session - // as the other methods specify calling 'OnRejectPromise' when they fail. - if (!aSessionId) { - Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) Failed to load session", aPromiseId); - mCallback->ResolveLoadSessionPromise(aPromiseId, false); - return; - } - Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d)", aPromiseId); auto iter = mPromiseIdToNewSessionTokens.find(aPromiseId); if (iter == mPromiseIdToNewSessionTokens.end()) { diff --git a/media/gmp-clearkey/0.1/AnnexB.cpp b/media/gmp-clearkey/0.1/AnnexB.cpp new file mode 100644 index 000000000000..952936deb27b --- /dev/null +++ b/media/gmp-clearkey/0.1/AnnexB.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AnnexB.h" +#include "BigEndian.h" + +#include + +using mozilla::BigEndian; + +static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 }; + +/* static */ void +AnnexB::ConvertFrameInPlace(std::vector& aBuffer) +{ + for (size_t i = 0; i < aBuffer.size() - 4 - sizeof(kAnnexBDelimiter) + 1; ) { + uint32_t nalLen = BigEndian::readUint32(&aBuffer[i]); + memcpy(&aBuffer[i], kAnnexBDelimiter, sizeof(kAnnexBDelimiter)); + i += nalLen + 4; + } +} + +static void +ConvertParamSetToAnnexB(std::vector::const_iterator& aIter, + size_t aCount, + std::vector& aOutAnnexB) +{ + for (size_t i = 0; i < aCount; i++) { + aOutAnnexB.insert(aOutAnnexB.end(), kAnnexBDelimiter, + kAnnexBDelimiter + sizeof(kAnnexBDelimiter)); + + uint16_t len = BigEndian::readUint16(&*aIter); aIter += 2; + aOutAnnexB.insert(aOutAnnexB.end(), aIter, aIter + len); aIter += len; + } +} + +/* static */ void +AnnexB::ConvertConfig(const std::vector& aBuffer, + std::vector& aOutAnnexB) +{ + // Skip past irrelevant headers + auto it = aBuffer.begin() + 5; + + if (it >= aBuffer.end()) { + return; + } + + size_t count = *(it++) & 31; + + // Check that we have enough bytes for the Annex B conversion + // and the next size field. Bail if not. + if (it + count * 2 >= aBuffer.end()) { + return; + } + + ConvertParamSetToAnnexB(it, count, aOutAnnexB); + + // Check that we have enough bytes for the Annex B conversion. + count = *(it++); + if (it + count * 2 > aBuffer.end()) { + aOutAnnexB.clear(); + return; + } + + ConvertParamSetToAnnexB(it, count, aOutAnnexB); +} diff --git a/media/gmp-clearkey/0.1/AnnexB.h b/media/gmp-clearkey/0.1/AnnexB.h new file mode 100644 index 000000000000..81ca87e0cf03 --- /dev/null +++ b/media/gmp-clearkey/0.1/AnnexB.h @@ -0,0 +1,32 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AnnexB_h__ +#define __AnnexB_h__ + +#include +#include + +class AnnexB +{ +public: + static void ConvertFrameInPlace(std::vector& aBuffer); + + static void ConvertConfig(const std::vector& aBuffer, + std::vector& aOutAnnexB); +}; + +#endif // __AnnexB_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp b/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp new file mode 100644 index 000000000000..ed1cac73888b --- /dev/null +++ b/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ClearKeyAsyncShutdown.h" +#include "gmp-task-utils.h" + +ClearKeyAsyncShutdown::ClearKeyAsyncShutdown(GMPAsyncShutdownHost *aHostAPI) + : mHost(aHostAPI) +{ + CK_LOGD("ClearKeyAsyncShutdown::ClearKeyAsyncShutdown"); + AddRef(); +} + +ClearKeyAsyncShutdown::~ClearKeyAsyncShutdown() +{ + CK_LOGD("ClearKeyAsyncShutdown::~ClearKeyAsyncShutdown"); +} + +void ShutdownTask(ClearKeyAsyncShutdown* aSelf, GMPAsyncShutdownHost* aHost) +{ + // Dumb implementation that just immediately reports completion. + // Real GMPs should ensure they are properly shutdown. + CK_LOGD("ClearKeyAsyncShutdown::BeginShutdown calling ShutdownComplete"); + aHost->ShutdownComplete(); + aSelf->Release(); +} + +void ClearKeyAsyncShutdown::BeginShutdown() +{ + CK_LOGD("ClearKeyAsyncShutdown::BeginShutdown dispatching asynchronous shutdown task"); + GetPlatform()->runonmainthread(WrapTaskNM(ShutdownTask, this, mHost)); +} diff --git a/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h b/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h new file mode 100644 index 000000000000..b828aae41d89 --- /dev/null +++ b/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h @@ -0,0 +1,37 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ClearKeyAsyncShutdown_h__ +#define __ClearKeyAsyncShutdown_h__ + +#include "gmp-api/gmp-async-shutdown.h" +#include "RefCounted.h" + +class ClearKeyAsyncShutdown : public GMPAsyncShutdown + , public RefCounted +{ +public: + explicit ClearKeyAsyncShutdown(GMPAsyncShutdownHost *aHostAPI); + + void BeginShutdown() override; + +private: + virtual ~ClearKeyAsyncShutdown(); + + GMPAsyncShutdownHost* mHost; +}; + +#endif // __ClearKeyAsyncShutdown_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyCDM.cpp b/media/gmp-clearkey/0.1/ClearKeyCDM.cpp deleted file mode 100644 index 8dbb941ed49e..000000000000 --- a/media/gmp-clearkey/0.1/ClearKeyCDM.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "ClearKeyCDM.h" - -#include "ClearKeyUtils.h" - -using namespace cdm; - -ClearKeyCDM::ClearKeyCDM(Host_8* aHost) -{ - mHost = aHost; - mSessionManager = new ClearKeySessionManager(mHost); -} - -void -ClearKeyCDM::Initialize(bool aAllowDistinctiveIdentifier, - bool aAllowPersistentState) -{ - mSessionManager->Init(aAllowDistinctiveIdentifier, - aAllowPersistentState); - -#ifdef ENABLE_WMF - mVideoDecoder = new VideoDecoder(mHost); -#endif -} - -void -ClearKeyCDM::SetServerCertificate(uint32_t aPromiseId, - const uint8_t* aServerCertificateData, - uint32_t aServerCertificateDataSize) -{ - mSessionManager->SetServerCertificate(aPromiseId, - aServerCertificateData, - aServerCertificateDataSize); -} - -void -ClearKeyCDM::CreateSessionAndGenerateRequest(uint32_t aPromiseId, - SessionType aSessionType, - InitDataType aInitDataType, - const uint8_t* aInitData, - uint32_t aInitDataSize) -{ - mSessionManager->CreateSession(aPromiseId, - aInitDataType, - aInitData, - aInitDataSize, - aSessionType); -} - -void -ClearKeyCDM::LoadSession(uint32_t aPromiseId, - SessionType aSessionType, - const char* aSessionId, - uint32_t aSessionIdSize) -{ - mSessionManager->LoadSession(aPromiseId, - aSessionId, - aSessionIdSize); -} - -void -ClearKeyCDM::UpdateSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize, - const uint8_t* aResponse, - uint32_t aResponseSize) -{ - mSessionManager->UpdateSession(aPromiseId, - aSessionId, - aSessionIdSize, - aResponse, - aResponseSize); -} - -void -ClearKeyCDM::CloseSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize) -{ - mSessionManager->CloseSession(aPromiseId, - aSessionId, - aSessionIdSize); -} - -void -ClearKeyCDM::RemoveSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize) -{ - mSessionManager->RemoveSession(aPromiseId, - aSessionId, - aSessionIdSize); -} - -void -ClearKeyCDM::TimerExpired(void* aContext) -{ - // Clearkey is not interested in timers, so this method has not been - // implemented. - assert(false); -} - -Status -ClearKeyCDM::Decrypt(const InputBuffer& aEncryptedBuffer, - DecryptedBlock* aDecryptedBuffer) -{ - return mSessionManager->Decrypt(aEncryptedBuffer, aDecryptedBuffer); -} - -Status -ClearKeyCDM::InitializeAudioDecoder( - const AudioDecoderConfig& aAudioDecoderConfig) -{ - // Audio decoding is not supported by Clearkey because Widevine doesn't - // support it and Clearkey's raison d'etre is to provide test coverage - // for paths that Widevine will exercise in the wild. - return Status::kDecodeError; -} - -Status -ClearKeyCDM::InitializeVideoDecoder( - const VideoDecoderConfig& aVideoDecoderConfig) -{ -#ifdef ENABLE_WMF - return mVideoDecoder->InitDecode(aVideoDecoderConfig); -#else - return Status::kDecodeError; -#endif -} - -void -ClearKeyCDM::DeinitializeDecoder(StreamType aDecoderType) -{ -#ifdef ENABLE_WMF - if (aDecoderType == StreamType::kStreamTypeVideo) { - mVideoDecoder->Reset(); - } -#endif -} - -void -ClearKeyCDM::ResetDecoder(StreamType aDecoderType) -{ -#ifdef ENABLE_WMF - if (aDecoderType == StreamType::kStreamTypeVideo) { - mVideoDecoder->Reset(); - } -#endif -} - -Status -ClearKeyCDM::DecryptAndDecodeFrame(const InputBuffer& aEncryptedBuffer, - VideoFrame* aVideoFrame) -{ -#ifdef ENABLE_WMF - return mVideoDecoder->Decode(aEncryptedBuffer, aVideoFrame); -#else - return Status::kDecodeError; -#endif -} - -Status -ClearKeyCDM::DecryptAndDecodeSamples(const InputBuffer& aEncryptedBuffer, - AudioFrames* aAudioFrame) -{ - // Audio decoding is not supported by Clearkey because Widevine doesn't - // support it and Clearkey's raison d'etre is to provide test coverage - // for paths that Widevine will exercise in the wild. - return Status::kDecodeError; -} - -void -ClearKeyCDM::OnPlatformChallengeResponse( - const PlatformChallengeResponse& aResponse) -{ - // This function should never be called and is not supported. - assert(false); -} - -void -ClearKeyCDM::OnQueryOutputProtectionStatus(QueryResult aResult, - uint32_t aLinkMask, - uint32_t aOutputProtectionMask) -{ - // This function should never be called and is not supported. - assert(false); -} - -void -ClearKeyCDM::Destroy() -{ - mSessionManager->DecryptingComplete(); -#ifdef ENABLE_WMF - mVideoDecoder->DecodingComplete(); -#endif -} \ No newline at end of file diff --git a/media/gmp-clearkey/0.1/ClearKeyCDM.h b/media/gmp-clearkey/0.1/ClearKeyCDM.h deleted file mode 100644 index 69515b62eaa9..000000000000 --- a/media/gmp-clearkey/0.1/ClearKeyCDM.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef ClearKeyCDM_h_ -#define ClearKeyCDM_h_ - -#include "ClearKeySessionManager.h" - -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" - -#ifdef ENABLE_WMF -#include "WMFUtils.h" -#include "VideoDecoder.h" -#endif - -class ClearKeyCDM : public cdm::ContentDecryptionModule_8 -{ -private: - RefPtr mSessionManager; -#ifdef ENABLE_WMF - RefPtr mVideoDecoder; -#endif - -protected: - cdm::Host_8* mHost; - -public: - explicit ClearKeyCDM(cdm::Host_8* mHost); - - void Initialize(bool aAllowDistinctiveIdentifier, - bool aAllowPersistentState) override; - - void SetServerCertificate(uint32_t aPromiseId, - const uint8_t* aServerCertificateData, - uint32_t aServerCertificateDataSize) - override; - - void CreateSessionAndGenerateRequest(uint32_t aPromiseId, - cdm::SessionType aSessionType, - cdm::InitDataType aInitDataType, - const uint8_t* aInitData, - uint32_t aInitDataSize) - override; - - void LoadSession(uint32_t aPromiseId, - cdm::SessionType aSessionType, - const char* aSessionId, - uint32_t aSessionIdSize) override; - - void UpdateSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize, - const uint8_t* aResponse, - uint32_t aResponseSize) override; - - void CloseSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize) override; - - void RemoveSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize) override; - - void TimerExpired(void* aContext) override; - - cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer, - cdm::DecryptedBlock* aDecryptedBuffer) override; - - cdm::Status InitializeAudioDecoder( - const cdm::AudioDecoderConfig& aAudioDecoderConfig) override; - - cdm::Status InitializeVideoDecoder( - const cdm::VideoDecoderConfig& aVideoDecoderConfig) override; - - void DeinitializeDecoder(cdm::StreamType aDecoderType) override; - - void ResetDecoder(cdm::StreamType aDecoderType) override; - - cdm::Status DecryptAndDecodeFrame( - const cdm::InputBuffer& aEncryptedBuffer, - cdm::VideoFrame* aVideoFrame) override; - - cdm::Status DecryptAndDecodeSamples( - const cdm::InputBuffer& aEncryptedBuffer, - cdm::AudioFrames* aAudioFrame) override; - - void OnPlatformChallengeResponse( - const cdm::PlatformChallengeResponse& aResponse) override; - - void - OnQueryOutputProtectionStatus(cdm::QueryResult aResult, - uint32_t aLinkMask, - uint32_t aOutputProtectionMask) override; - - void Destroy() override; -}; - -#endif \ No newline at end of file diff --git a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp index ee5f50865ac6..b72bf47e1d95 100644 --- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp @@ -14,15 +14,13 @@ * limitations under the License. */ -#include "ClearKeyDecryptionManager.h" - -#include "psshparser/PsshParser.h" - -#include #include #include -using namespace cdm; +#include "ClearKeyDecryptionManager.h" +#include "psshparser/PsshParser.h" +#include "gmp-api/gmp-decryption.h" +#include class ClearKeyDecryptor : public RefCounted { @@ -32,7 +30,7 @@ public: void InitKey(const Key& aKey); bool HasKey() const { return !!mKey.size(); } - Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, + GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, const CryptoMetaData& aMetadata); const Key& DecryptionKey() const { return mKey; } @@ -44,8 +42,7 @@ private: }; -/* static */ ClearKeyDecryptionManager* -ClearKeyDecryptionManager::sInstance = nullptr; +/* static */ ClearKeyDecryptionManager* ClearKeyDecryptionManager::sInstance = nullptr; /* static */ ClearKeyDecryptionManager* ClearKeyDecryptionManager::Get() @@ -76,17 +73,14 @@ ClearKeyDecryptionManager::~ClearKeyDecryptionManager() bool ClearKeyDecryptionManager::HasSeenKeyId(const KeyId& aKeyId) const { - CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s", - mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f"); + CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s", mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f"); return mDecryptors.find(aKeyId) != mDecryptors.end(); } bool ClearKeyDecryptionManager::IsExpectingKeyForKeyId(const KeyId& aKeyId) const { - CK_LOGARRAY("ClearKeyDecryptionManager::IsExpectingKeyForId ", - aKeyId.data(), - aKeyId.size()); + CK_LOGD("ClearKeyDecryptionManager::IsExpectingKeyForId %08x...", *(uint32_t*)&aKeyId[0]); const auto& decryptor = mDecryptors.find(aKeyId); return decryptor != mDecryptors.end() && !decryptor->second->HasKey(); } @@ -109,23 +103,16 @@ ClearKeyDecryptionManager::GetDecryptionKey(const KeyId& aKeyId) void ClearKeyDecryptionManager::InitKey(KeyId aKeyId, Key aKey) { - CK_LOGD("ClearKeyDecryptionManager::InitKey ", - aKeyId.data(), - aKeyId.size()); + CK_LOGD("ClearKeyDecryptionManager::InitKey %08x...", *(uint32_t*)&aKeyId[0]); if (IsExpectingKeyForKeyId(aKeyId)) { - CK_LOGARRAY("Initialized Key ", aKeyId.data(), aKeyId.size()); mDecryptors[aKeyId]->InitKey(aKey); - } else { - CK_LOGARRAY("Failed to initialize key ", aKeyId.data(), aKeyId.size()); } } void ClearKeyDecryptionManager::ExpectKeyId(KeyId aKeyId) { - CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId ", - aKeyId.data(), - aKeyId.size()); + CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId %08x...", *(uint32_t*)&aKeyId[0]); if (!HasSeenKeyId(aKeyId)) { mDecryptors[aKeyId] = new ClearKeyDecryptor(); } @@ -144,31 +131,23 @@ ClearKeyDecryptionManager::ReleaseKeyId(KeyId aKeyId) } } -Status +GMPErr ClearKeyDecryptionManager::Decrypt(std::vector& aBuffer, const CryptoMetaData& aMetadata) { return Decrypt(&aBuffer[0], aBuffer.size(), aMetadata); } -Status +GMPErr ClearKeyDecryptionManager::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, const CryptoMetaData& aMetadata) { CK_LOGD("ClearKeyDecryptionManager::Decrypt"); if (!HasKeyForKeyId(aMetadata.mKeyId)) { - CK_LOGARRAY("Unable to find decryptor for keyId: ", - aMetadata.mKeyId.data(), - aMetadata.mKeyId.size()); - return Status::kNoKey; + return GMPNoKeyErr; } - CK_LOGARRAY("Found decryptor for keyId: ", - aMetadata.mKeyId.data(), - aMetadata.mKeyId.size()); - return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer, - aBufferSize, - aMetadata); + return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer, aBufferSize, aMetadata); } ClearKeyDecryptor::ClearKeyDecryptor() @@ -179,9 +158,7 @@ ClearKeyDecryptor::ClearKeyDecryptor() ClearKeyDecryptor::~ClearKeyDecryptor() { if (HasKey()) { - CK_LOGARRAY("ClearKeyDecryptor dtor; key = ", - mKey.data(), - mKey.size()); + CK_LOGD("ClearKeyDecryptor dtor; key = %08x...", *(uint32_t*)&mKey[0]); } else { CK_LOGD("ClearKeyDecryptor dtor"); } @@ -193,7 +170,7 @@ ClearKeyDecryptor::InitKey(const Key& aKey) mKey = aKey; } -Status +GMPErr ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, const CryptoMetaData& aMetadata) { @@ -212,7 +189,7 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, uint32_t cipherBytes = aMetadata.mCipherBytes[i]; if (data + cipherBytes > aBuffer + aBufferSize) { // Trying to read past the end of the buffer! - return Status::kDecryptError; + return GMPCryptoErr; } memcpy(iter, data, cipherBytes); @@ -250,5 +227,5 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, memcpy(aBuffer, &tmp[0], aBufferSize); } - return Status::kSuccess; + return GMPNoErr; } diff --git a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h index 3c0668005fb6..7a6c9a560719 100644 --- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h +++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h @@ -17,43 +17,32 @@ #ifndef __ClearKeyDecryptionManager_h__ #define __ClearKeyDecryptionManager_h__ -#include "ClearKeyUtils.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" -#include "RefCounted.h" - #include +#include "ClearKeyUtils.h" +#include "RefCounted.h" + class ClearKeyDecryptor; -class CryptoMetaData -{ +class CryptoMetaData { public: CryptoMetaData() {} - explicit CryptoMetaData(const cdm::InputBuffer* aInputBuffer) + explicit CryptoMetaData(const GMPEncryptedBufferMetadata* aCrypto) { - Init(aInputBuffer); + Init(aCrypto); } - void Init(const cdm::InputBuffer* aInputBuffer) + void Init(const GMPEncryptedBufferMetadata* aCrypto) { - if (!aInputBuffer) { + if (!aCrypto) { assert(!IsValid()); return; } - - Assign(mKeyId, aInputBuffer->key_id, aInputBuffer->key_id_size); - Assign(mIV, aInputBuffer->iv, aInputBuffer->iv_size); - - for (uint32_t i = 0; i < aInputBuffer->num_subsamples; ++i) { - const cdm::SubsampleEntry& subsample = aInputBuffer->subsamples[i]; - - mCipherBytes.push_back(subsample.cipher_bytes); - mClearBytes.push_back(subsample.clear_bytes); - } + Assign(mKeyId, aCrypto->KeyId(), aCrypto->KeyIdSize()); + Assign(mIV, aCrypto->IV(), aCrypto->IVSize()); + Assign(mClearBytes, aCrypto->ClearBytes(), aCrypto->NumSubsamples()); + Assign(mCipherBytes, aCrypto->CipherBytes(), aCrypto->NumSubsamples()); } bool IsValid() const { @@ -70,7 +59,7 @@ public: std::vector mKeyId; std::vector mIV; - std::vector mClearBytes; + std::vector mClearBytes; std::vector mCipherBytes; }; @@ -96,10 +85,12 @@ public: void ReleaseKeyId(KeyId aKeyId); // Decrypts buffer *in place*. - cdm::Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, - const CryptoMetaData& aMetadata); - cdm::Status Decrypt(std::vector& aBuffer, - const CryptoMetaData& aMetadata); + GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize, + const CryptoMetaData& aMetadata); + GMPErr Decrypt(std::vector& aBuffer, + const CryptoMetaData& aMetadata); + + void Shutdown(); private: bool IsExpectingKeyForKeyId(const KeyId& aKeyId) const; diff --git a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp index 1a2194162b62..2e14d822ee46 100644 --- a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp @@ -15,123 +15,81 @@ */ #include "ClearKeyPersistence.h" - #include "ClearKeyUtils.h" #include "ClearKeyStorage.h" #include "ClearKeySessionManager.h" #include "RefCounted.h" -#include #include -#include #include +#include +#include +#include +#include using namespace std; -using namespace cdm; -void -ClearKeyPersistence::ReadAllRecordsFromIndex(function&& aOnComplete) { - // Clear what we think the index file contains, we're about to read it again. - mPersistentSessionIds.clear(); +// Whether we've loaded the persistent session ids from GMPStorage yet. +enum PersistentKeyState { + UNINITIALIZED, + LOADING, + LOADED +}; +static PersistentKeyState sPersistentKeyState = UNINITIALIZED; - // Hold a reference to the persistence manager, so it isn't released before - // we try and use it. - RefPtr self(this); - function onIndexSuccess = - [self, aOnComplete] (const uint8_t* data, uint32_t size) - { - CK_LOGD("ClearKeyPersistence: Loaded index file!"); - const char* charData = (const char*)data; +// Set of session Ids of the persistent sessions created or residing in +// storage. +static set sPersistentSessionIds; - stringstream ss(string(charData, charData + size)); - string name; - while (getline(ss, name)) { - if (ClearKeyUtils::IsValidSessionId(name.data(), name.size())) { - self->mPersistentSessionIds.insert(atoi(name.c_str())); +static vector sTasksBlockedOnSessionIdLoad; + +static void +ReadAllRecordsFromIterator(GMPRecordIterator* aRecordIterator, + void* aUserArg, + GMPErr aStatus) +{ + assert(sPersistentKeyState == LOADING); + if (GMP_SUCCEEDED(aStatus)) { + // Extract the record names which are valid uint32_t's; they're + // the persistent session ids. + const char* name = nullptr; + uint32_t len = 0; + while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) { + if (ClearKeyUtils::IsValidSessionId(name, len)) { + assert(name[len] == 0); + sPersistentSessionIds.insert(atoi(name)); } + aRecordIterator->NextRecord(); } - - self->mPersistentKeyState = PersistentKeyState::LOADED; - aOnComplete(); - }; - - function onIndexFailed = - [self, aOnComplete] () - { - CK_LOGD("ClearKeyPersistence: Failed to load index file (it might not exist"); - self->mPersistentKeyState = PersistentKeyState::LOADED; - aOnComplete(); - }; - - string filename = "index"; - ReadData(mHost, filename, move(onIndexSuccess), move(onIndexFailed)); -} - -void -ClearKeyPersistence::WriteIndex() { - function onIndexSuccess = - [] () - { - CK_LOGD("ClearKeyPersistence: Wrote index file"); - }; - - function onIndexFail = - [] () - { - CK_LOGD("ClearKeyPersistence: Failed to write index file (this is bad)"); - }; - - stringstream ss; - - for (const uint32_t& sessionId : mPersistentSessionIds) { - ss << sessionId; - ss << '\n'; } + sPersistentKeyState = LOADED; + aRecordIterator->Close(); - string dataString = ss.str(); - uint8_t* dataArray = (uint8_t*)dataString.data(); - vector data(dataArray, dataArray + dataString.size()); - - string filename = "index"; - WriteData(mHost, - filename, - data, - move(onIndexSuccess), - move(onIndexFail)); + for (size_t i = 0; i < sTasksBlockedOnSessionIdLoad.size(); i++) { + sTasksBlockedOnSessionIdLoad[i]->Run(); + sTasksBlockedOnSessionIdLoad[i]->Destroy(); + } + sTasksBlockedOnSessionIdLoad.clear(); } - -ClearKeyPersistence::ClearKeyPersistence(Host_8* aHost) +/* static */ void +ClearKeyPersistence::EnsureInitialized() { - this->mHost = aHost; -} - -void -ClearKeyPersistence::EnsureInitialized(bool aPersistentStateAllowed, - function&& aOnInitialized) -{ - if (aPersistentStateAllowed && - mPersistentKeyState == PersistentKeyState::UNINITIALIZED) { - mPersistentKeyState = LOADING; - ReadAllRecordsFromIndex(move(aOnInitialized)); - } else { - mPersistentKeyState = PersistentKeyState::LOADED; - aOnInitialized(); + if (sPersistentKeyState == UNINITIALIZED) { + sPersistentKeyState = LOADING; + if (GMP_FAILED(EnumRecordNames(&ReadAllRecordsFromIterator))) { + sPersistentKeyState = LOADED; + } } } -bool ClearKeyPersistence::IsLoaded() const -{ - return mPersistentKeyState == PersistentKeyState::LOADED; -} - -string -ClearKeyPersistence::GetNewSessionId(SessionType aSessionType) +/* static */ string +ClearKeyPersistence::GetNewSessionId(GMPSessionType aSessionType) { static uint32_t sNextSessionId = 1; // Ensure we don't re-use a session id that was persisted. - while (Contains(mPersistentSessionIds, sNextSessionId)) { + while (Contains(sPersistentSessionIds, sNextSessionId)) { sNextSessionId++; } @@ -140,11 +98,8 @@ ClearKeyPersistence::GetNewSessionId(SessionType aSessionType) ss << sNextSessionId; ss >> sessionId; - if (aSessionType == SessionType::kPersistentLicense) { - mPersistentSessionIds.insert(sNextSessionId); - - // Save the updated index file. - WriteIndex(); + if (aSessionType == kGMPPersistentSession) { + sPersistentSessionIds.insert(sNextSessionId); } sNextSessionId++; @@ -152,17 +107,154 @@ ClearKeyPersistence::GetNewSessionId(SessionType aSessionType) return sessionId; } -bool + +class CreateSessionTask : public GMPTask { +public: + CreateSessionTask(ClearKeySessionManager* aTarget, + uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const string& aInitDataType, + const uint8_t* aInitData, + uint32_t aInitDataSize, + GMPSessionType aSessionType) + : mTarget(aTarget) + , mCreateSessionToken(aCreateSessionToken) + , mPromiseId(aPromiseId) + , mInitDataType(aInitDataType) + , mSessionType(aSessionType) + { + mInitData.insert(mInitData.end(), + aInitData, + aInitData + aInitDataSize); + } + virtual void Run() override { + mTarget->CreateSession(mCreateSessionToken, + mPromiseId, + mInitDataType.c_str(), + mInitDataType.size(), + &mInitData.front(), + mInitData.size(), + mSessionType); + } + virtual void Destroy() override { + delete this; + } +private: + RefPtr mTarget; + uint32_t mCreateSessionToken; + uint32_t mPromiseId; + const string mInitDataType; + vector mInitData; + GMPSessionType mSessionType; +}; + + +/* static */ bool +ClearKeyPersistence::DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance, + uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const string& aInitDataType, + const uint8_t* aInitData, + uint32_t aInitDataSize, + GMPSessionType aSessionType) +{ + if (sPersistentKeyState >= LOADED) { + return false; + } + GMPTask* t = new CreateSessionTask(aInstance, + aCreateSessionToken, + aPromiseId, + aInitDataType, + aInitData, + aInitDataSize, + aSessionType); + sTasksBlockedOnSessionIdLoad.push_back(t); + return true; +} + +class LoadSessionTask : public GMPTask { +public: + LoadSessionTask(ClearKeySessionManager* aTarget, + uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength) + : mTarget(aTarget) + , mPromiseId(aPromiseId) + , mSessionId(aSessionId, aSessionId + aSessionIdLength) + { + } + virtual void Run() override { + mTarget->LoadSession(mPromiseId, + mSessionId.c_str(), + mSessionId.size()); + } + virtual void Destroy() override { + delete this; + } +private: + RefPtr mTarget; + uint32_t mPromiseId; + string mSessionId; +}; + +/* static */ bool +ClearKeyPersistence::DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance, + uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength) +{ + if (sPersistentKeyState >= LOADED) { + return false; + } + GMPTask* t = new LoadSessionTask(aInstance, + aPromiseId, + aSessionId, + aSessionIdLength); + sTasksBlockedOnSessionIdLoad.push_back(t); + return true; +} + +/* static */ bool ClearKeyPersistence::IsPersistentSessionId(const string& aSessionId) { - return Contains(mPersistentSessionIds, atoi(aSessionId.c_str())); + return Contains(sPersistentSessionIds, atoi(aSessionId.c_str())); } -void -ClearKeyPersistence::PersistentSessionRemoved(string& aSessionId) +class LoadSessionFromKeysTask : public ReadContinuation { +public: + LoadSessionFromKeysTask(ClearKeySessionManager* aTarget, + const string& aSessionId, + uint32_t aPromiseId) + : mTarget(aTarget) + , mSessionId(aSessionId) + , mPromiseId(aPromiseId) + { + } + + virtual void ReadComplete(GMPErr aStatus, + const uint8_t* aData, + uint32_t aLength) override + { + mTarget->PersistentSessionDataLoaded(aStatus, mPromiseId, mSessionId, aData, aLength); + } +private: + RefPtr mTarget; + string mSessionId; + uint32_t mPromiseId; +}; + +/* static */ void +ClearKeyPersistence::LoadSessionData(ClearKeySessionManager* aInstance, + const string& aSid, + uint32_t aPromiseId) { - mPersistentSessionIds.erase(atoi(aSessionId.c_str())); - - // Update the index file. - WriteIndex(); + LoadSessionFromKeysTask* loadTask = + new LoadSessionFromKeysTask(aInstance, aSid, aPromiseId); + ReadData(aSid, loadTask); +} + +/* static */ void +ClearKeyPersistence::PersistentSessionRemoved(const string& aSessionId) +{ + sPersistentSessionIds.erase(atoi(aSessionId.c_str())); } diff --git a/media/gmp-clearkey/0.1/ClearKeyPersistence.h b/media/gmp-clearkey/0.1/ClearKeyPersistence.h index 0190b0f139c2..ddab9f783c1d 100644 --- a/media/gmp-clearkey/0.1/ClearKeyPersistence.h +++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.h @@ -17,51 +17,37 @@ #ifndef __ClearKeyPersistence_h__ #define __ClearKeyPersistence_h__ -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" -#include "RefCounted.h" - -#include -#include #include -#include - +#include "gmp-api/gmp-decryption.h" class ClearKeySessionManager; -// Whether we've loaded the persistent session ids yet. -enum PersistentKeyState { - UNINITIALIZED, - LOADING, - LOADED -}; - -class ClearKeyPersistence : public RefCounted -{ +class ClearKeyPersistence { public: - explicit ClearKeyPersistence(cdm::Host_8* aHost); + static void EnsureInitialized(); - void EnsureInitialized(bool aPersistentStateAllowed, - std::function&& aOnInitialized); + static std::string GetNewSessionId(GMPSessionType aSessionType); - bool IsLoaded() const; + static bool DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance, + uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const std::string& aInitDataType, + const uint8_t* aInitData, + uint32_t aInitDataSize, + GMPSessionType aSessionType); - std::string GetNewSessionId(cdm::SessionType aSessionType); + static bool DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance, + uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength); - bool IsPersistentSessionId(const std::string& aSid); + static bool IsPersistentSessionId(const std::string& aSid); - void PersistentSessionRemoved(std::string& aSid); -private: - cdm::Host_8* mHost = nullptr; + static void LoadSessionData(ClearKeySessionManager* aInstance, + const std::string& aSid, + uint32_t aPromiseId); - PersistentKeyState mPersistentKeyState = PersistentKeyState::UNINITIALIZED; - - std::set mPersistentSessionIds; - - void ReadAllRecordsFromIndex(std::function&& aOnComplete); - void WriteIndex(); + static void PersistentSessionRemoved(const std::string& aSid); }; #endif // __ClearKeyPersistence_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeySession.cpp b/media/gmp-clearkey/0.1/ClearKeySession.cpp index 54fb1bcb47bc..fb45dd2ebfd8 100644 --- a/media/gmp-clearkey/0.1/ClearKeySession.cpp +++ b/media/gmp-clearkey/0.1/ClearKeySession.cpp @@ -20,17 +20,18 @@ #include "ClearKeyUtils.h" #include "ClearKeyStorage.h" #include "psshparser/PsshParser.h" - +#include "gmp-task-utils.h" +#include "gmp-api/gmp-decryption.h" #include #include using namespace mozilla; -using namespace cdm; -using namespace std; ClearKeySession::ClearKeySession(const std::string& aSessionId, - SessionType aSessionType) + GMPDecryptorCallback* aCallback, + GMPSessionType aSessionType) : mSessionId(aSessionId) + , mCallback(aCallback) , mSessionType(aSessionType) { CK_LOGD("ClearKeySession ctor %p", this); @@ -39,21 +40,30 @@ ClearKeySession::ClearKeySession(const std::string& aSessionId, ClearKeySession::~ClearKeySession() { CK_LOGD("ClearKeySession dtor %p", this); + + std::vector key_infos; + for (const KeyId& keyId : mKeyIds) { + assert(ClearKeyDecryptionManager::Get()->HasSeenKeyId(keyId)); + ClearKeyDecryptionManager::Get()->ReleaseKeyId(keyId); + key_infos.push_back(GMPMediaKeyInfo(&keyId[0], keyId.size(), kGMPUnknown)); + } + mCallback->BatchedKeyStatusChanged(&mSessionId[0], mSessionId.size(), + key_infos.data(), key_infos.size()); } -bool -ClearKeySession::Init(InitDataType aInitDataType, - const uint8_t* aInitData, - uint32_t aInitDataSize) +void +ClearKeySession::Init(uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const std::string& aInitDataType, + const uint8_t* aInitData, uint32_t aInitDataSize) { CK_LOGD("ClearKeySession::Init"); - if (aInitDataType == InitDataType::kCenc) { + if (aInitDataType == "cenc") { ParseCENCInitData(aInitData, aInitDataSize, mKeyIds); - } else if (aInitDataType == InitDataType::kKeyIds) { + } else if (aInitDataType == "keyids") { ClearKeyUtils::ParseKeyIdsInitData(aInitData, aInitDataSize, mKeyIds); - } else if (aInitDataType == InitDataType::kWebM && - aInitDataSize <= kMaxWebmInitDataSize) { + } else if (aInitDataType == "webm" && aInitDataSize <= kMaxWebmInitDataSize) { // "webm" initData format is simply the raw bytes of the keyId. vector keyId; keyId.assign(aInitData, aInitData+aInitDataSize); @@ -61,13 +71,17 @@ ClearKeySession::Init(InitDataType aInitDataType, } if (!mKeyIds.size()) { - return false; + const char message[] = "Couldn't parse init data"; + mCallback->RejectPromise(aPromiseId, kGMPTypeError, message, strlen(message)); + return; } - return true; + mCallback->SetSessionId(aCreateSessionToken, &mSessionId[0], mSessionId.length()); + + mCallback->ResolvePromise(aPromiseId); } -SessionType +GMPSessionType ClearKeySession::Type() const { return mSessionType; diff --git a/media/gmp-clearkey/0.1/ClearKeySession.h b/media/gmp-clearkey/0.1/ClearKeySession.h index 8647273b851d..2783b2253b19 100644 --- a/media/gmp-clearkey/0.1/ClearKeySession.h +++ b/media/gmp-clearkey/0.1/ClearKeySession.h @@ -18,28 +18,30 @@ #define __ClearKeySession_h__ #include "ClearKeyUtils.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" +#include "gmp-api/gmp-decryption.h" -#include -#include +class GMPBuffer; +class GMPDecryptorCallback; +class GMPDecryptorHost; +class GMPEncryptedBufferMetadata; class ClearKeySession { public: explicit ClearKeySession(const std::string& aSessionId, - cdm::SessionType aSessionType); + GMPDecryptorCallback* aCallback, + GMPSessionType aSessionType); ~ClearKeySession(); const std::vector& GetKeyIds() const { return mKeyIds; } - bool Init(cdm::InitDataType aInitDataType, + void Init(uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const string& aInitDataType, const uint8_t* aInitData, uint32_t aInitDataSize); - cdm::SessionType Type() const; + GMPSessionType Type() const; void AddKeyId(const KeyId& aKeyId); @@ -49,7 +51,8 @@ private: const std::string mSessionId; std::vector mKeyIds; - const cdm::SessionType mSessionType; + GMPDecryptorCallback* mCallback; + const GMPSessionType mSessionType; }; #endif // __ClearKeySession_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp index a724e27fc989..4dbb062992af 100644 --- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp +++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp @@ -14,33 +14,30 @@ * limitations under the License. */ +#include +#include +#include + #include "ClearKeyDecryptionManager.h" #include "ClearKeySessionManager.h" #include "ClearKeyUtils.h" #include "ClearKeyStorage.h" #include "ClearKeyPersistence.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" -#include "psshparser/PsshParser.h" - +#include "gmp-task-utils.h" #include -#include -#include -#include using namespace std; -using namespace cdm; -ClearKeySessionManager::ClearKeySessionManager(Host_8* aHost) +ClearKeySessionManager::ClearKeySessionManager() : mDecryptionManager(ClearKeyDecryptionManager::Get()) { CK_LOGD("ClearKeySessionManager ctor %p", this); AddRef(); - mHost = aHost; - mPersistence = new ClearKeyPersistence(mHost); + if (GetPlatform()->createthread(&mThread) != GMPNoErr) { + CK_LOGD("failed to create thread in clearkey cdm"); + mThread = nullptr; + } } ClearKeySessionManager::~ClearKeySessionManager() @@ -49,106 +46,56 @@ ClearKeySessionManager::~ClearKeySessionManager() } void -ClearKeySessionManager::Init(bool aDistinctiveIdentifierAllowed, +ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierAllowed, bool aPersistentStateAllowed) { CK_LOGD("ClearKeySessionManager::Init"); - - RefPtr self(this); - function onPersistentStateLoaded = - [self] () - { - while (!self->mDeferredInitialize.empty()) { - function func = self->mDeferredInitialize.front(); - self->mDeferredInitialize.pop(); - - func(); - } - }; - - mPersistence->EnsureInitialized(aPersistentStateAllowed, - move(onPersistentStateLoaded)); + mCallback = aCallback; + ClearKeyPersistence::EnsureInitialized(); } void -ClearKeySessionManager::CreateSession(uint32_t aPromiseId, - InitDataType aInitDataType, +ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const char* aInitDataType, + uint32_t aInitDataTypeSize, const uint8_t* aInitData, uint32_t aInitDataSize, - SessionType aSessionType) + GMPSessionType aSessionType) { - // Copy the init data so it is correctly captured by the lambda - vector initData(aInitData, aInitData + aInitDataSize); - - RefPtr self(this); - function deferrer = - [self, aPromiseId, aInitDataType, initData, aSessionType] () - { - self->CreateSession(aPromiseId, - aInitDataType, - initData.data(), - initData.size(), - aSessionType); - }; - - // If we haven't loaded, don't do this yet - if (MaybeDeferTillInitialized(deferrer)) { - return; - } - CK_LOGD("ClearKeySessionManager::CreateSession type:%s", aInitDataType); - CK_LOGARRAY("ClearKeySessionManager::CreateSession initdata: ", - aInitData, - aInitDataSize); - - // If 'DecryptingComplete' has been called mHost will be null so we can't - // won't be able to resolve our promise - if (!mHost) { - CK_LOGD("ClearKeySessionManager::CreateSession: mHost is nullptr") - return; - } - + string initDataType(aInitDataType, aInitDataType + aInitDataTypeSize); // initDataType must be "cenc", "keyids", or "webm". - if (aInitDataType != InitDataType::kCenc && - aInitDataType != InitDataType::kKeyIds && - aInitDataType != InitDataType::kWebM) { - - string message = "initDataType is not supported by ClearKey"; - mHost->OnRejectPromise(aPromiseId, - Error::kNotSupportedError, - 0, - message.c_str(), - message.size()); - + if (initDataType != "cenc" && + initDataType != "keyids" && + initDataType != "webm") { + string message = "'" + initDataType + "' is an initDataType unsupported by ClearKey"; + mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError, + message.c_str(), message.size()); return; } - string sessionId = mPersistence->GetNewSessionId(aSessionType); + if (ClearKeyPersistence::DeferCreateSessionIfNotReady(this, + aCreateSessionToken, + aPromiseId, + initDataType, + aInitData, + aInitDataSize, + aSessionType)) { + return; + } + + string sessionId = ClearKeyPersistence::GetNewSessionId(aSessionType); assert(mSessions.find(sessionId) == mSessions.end()); - ClearKeySession* session = new ClearKeySession(sessionId, - aSessionType); - - if (!session->Init(aInitDataType, aInitData, aInitDataSize)) { - - CK_LOGD("Failed to initialize session: %s", sessionId.c_str()); - - const static char* message = "Failed to initialize session"; - mHost->OnRejectPromise(aPromiseId, - Error::kUnknownError, - 0, - message, - strlen(message)); - - return; - } - + ClearKeySession* session = new ClearKeySession(sessionId, mCallback, aSessionType); + session->Init(aCreateSessionToken, aPromiseId, initDataType, aInitData, aInitDataSize); mSessions[sessionId] = session; const vector& sessionKeys = session->GetKeyIds(); vector neededKeys; - for (auto it = sessionKeys.begin(); it != sessionKeys.end(); it++) { // Need to request this key ID from the client. We always send a key // request, whether or not another session has sent a request with the same @@ -166,19 +113,9 @@ ClearKeySessionManager::CreateSession(uint32_t aPromiseId, // Send a request for needed key data. string request; ClearKeyUtils::MakeKeyRequest(neededKeys, request, aSessionType); - - // Resolve the promise with the new session information. - mHost->OnResolveNewSessionPromise(aPromiseId, - sessionId.c_str(), - sessionId.size()); - - mHost->OnSessionMessage(sessionId.c_str(), - sessionId.size(), - MessageType::kLicenseRequest, - request.c_str(), - request.size(), - nullptr, - 0); + mCallback->SessionMessage(&sessionId[0], sessionId.length(), + kGMPLicenseRequest, + (uint8_t*)&request[0], request.length()); } void @@ -186,90 +123,53 @@ ClearKeySessionManager::LoadSession(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdLength) { - // Copy the sessionId into a string so the lambda captures it properly. - string sessionId(aSessionId, aSessionId + aSessionIdLength); - - // Hold a reference to the SessionManager so that it isn't released before - // we try to use it. - RefPtr self(this); - function deferrer = - [self, aPromiseId, sessionId] () - { - self->LoadSession(aPromiseId, sessionId.data(), sessionId.size()); - }; - - if (MaybeDeferTillInitialized(deferrer)) { - return; - } - CK_LOGD("ClearKeySessionManager::LoadSession"); - // If the SessionManager has been shutdown mHost will be null and we won't - // be able to resolve the promise. - if (!mHost) { - return; - } - if (!ClearKeyUtils::IsValidSessionId(aSessionId, aSessionIdLength)) { - mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0); + mCallback->ResolveLoadSessionPromise(aPromiseId, false); return; } - if (!mPersistence->IsPersistentSessionId(sessionId)) { - mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0); + if (ClearKeyPersistence::DeferLoadSessionIfNotReady(this, + aPromiseId, + aSessionId, + aSessionIdLength)) { return; } - function success = - [self, sessionId, aPromiseId] (const uint8_t* data, uint32_t size) - { - self->PersistentSessionDataLoaded(aPromiseId, - sessionId, - data, - size); - }; + string sid(aSessionId, aSessionId + aSessionIdLength); + if (!ClearKeyPersistence::IsPersistentSessionId(sid)) { + mCallback->ResolveLoadSessionPromise(aPromiseId, false); + return; + } - function failure = [self, sessionId, aPromiseId] { - if (!self->mHost) { - return; - } - // As per the API described in ContentDecryptionModule_8 - self->mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0); - }; - - ReadData(mHost, sessionId, move(success), move(failure)); + // Callsback PersistentSessionDataLoaded with results... + ClearKeyPersistence::LoadSessionData(this, sid, aPromiseId); } void -ClearKeySessionManager::PersistentSessionDataLoaded(uint32_t aPromiseId, +ClearKeySessionManager::PersistentSessionDataLoaded(GMPErr aStatus, + uint32_t aPromiseId, const string& aSessionId, const uint8_t* aKeyData, uint32_t aKeyDataSize) { CK_LOGD("ClearKeySessionManager::PersistentSessionDataLoaded"); - - // Check that the SessionManager has not been shut down before we try and - // resolve any promises. - if (!mHost) { - return; - } - - if (Contains(mSessions, aSessionId) || + if (GMP_FAILED(aStatus) || + Contains(mSessions, aSessionId) || (aKeyDataSize % (2 * CENC_KEY_LEN)) != 0) { - - // As per the instructions in ContentDecryptionModule_8 - mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0); + mCallback->ResolveLoadSessionPromise(aPromiseId, false); return; } ClearKeySession* session = new ClearKeySession(aSessionId, - SessionType::kPersistentLicense); - + mCallback, + kGMPPersistentSession); mSessions[aSessionId] = session; uint32_t numKeys = aKeyDataSize / (2 * CENC_KEY_LEN); - vector keyInfos; + vector key_infos; vector keyPairs; for (uint32_t i = 0; i < numKeys; i ++) { const uint8_t* base = aKeyData + 2 * CENC_KEY_LEN * i; @@ -287,25 +187,16 @@ ClearKeySessionManager::PersistentSessionDataLoaded(uint32_t aPromiseId, mDecryptionManager->ExpectKeyId(keyPair.mKeyId); mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey); mKeyIds.insert(keyPair.mKey); + keyPairs.push_back(keyPair); - - KeyInformation keyInfo = KeyInformation(); - keyInfo.key_id = &keyPairs.back().mKeyId[0]; - keyInfo.key_id_size = keyPair.mKeyId.size(); - keyInfo.status = KeyStatus::kUsable; - - keyInfos.push_back(keyInfo); + key_infos.push_back(GMPMediaKeyInfo(&keyPairs[i].mKeyId[0], + keyPairs[i].mKeyId.size(), + kGMPUsable)); } + mCallback->BatchedKeyStatusChanged(&aSessionId[0], aSessionId.size(), + key_infos.data(), key_infos.size()); - mHost->OnSessionKeysChange(&aSessionId[0], - aSessionId.size(), - true, - keyInfos.data(), - keyInfos.size()); - - mHost->OnResolveNewSessionPromise(aPromiseId, - aSessionId.c_str(), - aSessionId.size()); + mCallback->ResolveLoadSessionPromise(aPromiseId, true); } void @@ -315,47 +206,13 @@ ClearKeySessionManager::UpdateSession(uint32_t aPromiseId, const uint8_t* aResponse, uint32_t aResponseSize) { - // Copy the method arguments so we can capture them in the lambda - string sessionId(aSessionId, aSessionId + aSessionIdLength); - vector response(aResponse, aResponse + aResponseSize); - - // Hold a reference to the SessionManager so it isn't released before we - // callback. - RefPtr self(this); - function deferrer = - [self, aPromiseId, sessionId, response] () - { - self->UpdateSession(aPromiseId, - sessionId.data(), - sessionId.size(), - response.data(), - response.size()); - }; - - // If we haven't fully loaded, defer calling this method - if (MaybeDeferTillInitialized(deferrer)) { - return; - } - - // Make sure the SessionManager has not been shutdown before we try and - // resolve any promises. - if (!mHost) { - return; - } - CK_LOGD("ClearKeySessionManager::UpdateSession"); - CK_LOGD("Updating session: %s", sessionId.c_str()); + string sessionId(aSessionId, aSessionId + aSessionIdLength); auto itr = mSessions.find(sessionId); if (itr == mSessions.end() || !(itr->second)) { CK_LOGW("ClearKey CDM couldn't resolve session ID in UpdateSession."); - CK_LOGD("Unable to find session: %s", sessionId.c_str()); - mHost->OnRejectPromise(aPromiseId, - Error::kInvalidAccessError, - 0, - nullptr, - 0); - + mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0); return; } ClearKeySession* session = itr->second; @@ -363,56 +220,32 @@ ClearKeySessionManager::UpdateSession(uint32_t aPromiseId, // Verify the size of session response. if (aResponseSize >= kMaxSessionResponseLength) { CK_LOGW("Session response size is not within a reasonable size."); - CK_LOGD("Failed to parse response for session %s", sessionId.c_str()); - - mHost->OnRejectPromise(aPromiseId, - Error::kInvalidAccessError, - 0, - nullptr, - 0); - + mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0); return; } // Parse the response for any (key ID, key) pairs. vector keyPairs; - if (!ClearKeyUtils::ParseJWK(aResponse, - aResponseSize, - keyPairs, - session->Type())) { + if (!ClearKeyUtils::ParseJWK(aResponse, aResponseSize, keyPairs, session->Type())) { CK_LOGW("ClearKey CDM failed to parse JSON Web Key."); - - mHost->OnRejectPromise(aPromiseId, - Error::kInvalidAccessError, - 0, - nullptr, - 0); - + mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0); return; } - vector keyInfos; + vector key_infos; for (size_t i = 0; i < keyPairs.size(); i++) { KeyIdPair& keyPair = keyPairs[i]; mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey); mKeyIds.insert(keyPair.mKeyId); - - KeyInformation keyInfo = KeyInformation(); - keyInfo.key_id = &keyPair.mKeyId[0]; - keyInfo.key_id_size = keyPair.mKeyId.size(); - keyInfo.status = KeyStatus::kUsable; - - keyInfos.push_back(keyInfo); + key_infos.push_back(GMPMediaKeyInfo(&keyPair.mKeyId[0], + keyPair.mKeyId.size(), + kGMPUsable)); } + mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdLength, + key_infos.data(), key_infos.size()); - mHost->OnSessionKeysChange(aSessionId, - aSessionIdLength, - true, - keyInfos.data(), - keyInfos.size()); - - if (session->Type() != SessionType::kPersistentLicense) { - mHost->OnResolvePromise(aPromiseId); + if (session->Type() != kGMPPersistentSession) { + mCallback->ResolvePromise(aPromiseId); return; } @@ -420,30 +253,15 @@ ClearKeySessionManager::UpdateSession(uint32_t aPromiseId, // and simply append each keyId followed by its key. vector keydata; Serialize(session, keydata); - - function resolve = [self, aPromiseId] () - { - if (!self->mHost) { - return; - } - self->mHost->OnResolvePromise(aPromiseId); - }; - - function reject = [self, aPromiseId] () - { - if (!self->mHost) { - return; - } - - static const char* message = "Couldn't store cenc key init data"; - self->mHost->OnRejectPromise(aPromiseId, - Error::kInvalidStateError, - 0, - message, - strlen(message)); - }; - - WriteData(mHost, sessionId, keydata, move(resolve), move(reject)); + GMPTask* resolve = WrapTask(mCallback, &GMPDecryptorCallback::ResolvePromise, aPromiseId); + static const char* message = "Couldn't store cenc key init data"; + GMPTask* reject = WrapTask(mCallback, + &GMPDecryptorCallback::RejectPromise, + aPromiseId, + kGMPInvalidStateError, + message, + strlen(message)); + StoreData(sessionId, keydata, resolve, reject); } void @@ -469,39 +287,13 @@ ClearKeySessionManager::CloseSession(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdLength) { - // Copy the sessionId into a string so we capture it properly. - string sessionId(aSessionId, aSessionId + aSessionIdLength); - // Hold a reference to the session manager, so it doesn't get deleted - // before we need to use it. - RefPtr self(this); - function deferrer = - [self, aPromiseId, sessionId] () - { - self->CloseSession(aPromiseId, sessionId.data(), sessionId.size()); - }; - - // If we haven't loaded, call this method later. - if (MaybeDeferTillInitialized(deferrer)) { - return; - } - CK_LOGD("ClearKeySessionManager::CloseSession"); - // If DecryptingComplete has been called mHost will be null and we won't - // be able to resolve our promise. - if (!mHost) { - return; - } - + string sessionId(aSessionId, aSessionId + aSessionIdLength); auto itr = mSessions.find(sessionId); if (itr == mSessions.end()) { CK_LOGW("ClearKey CDM couldn't close non-existent session."); - mHost->OnRejectPromise(aPromiseId, - Error::kInvalidAccessError, - 0, - nullptr, - 0); - + mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0); return; } @@ -509,9 +301,8 @@ ClearKeySessionManager::CloseSession(uint32_t aPromiseId, assert(session); ClearInMemorySessionData(session); - - mHost->OnSessionClosed(aSessionId, aSessionIdLength); - mHost->OnResolvePromise(aPromiseId); + mCallback->SessionClosed(aSessionId, aSessionIdLength); + mCallback->ResolvePromise(aPromiseId); } void @@ -526,80 +317,40 @@ ClearKeySessionManager::RemoveSession(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdLength) { - // Copy the sessionId into a string so it can be captured for the lambda. - string sessionId(aSessionId, aSessionId + aSessionIdLength); - - // Hold a reference to the SessionManager, so it isn't released before we - // try and use it. - RefPtr self(this); - function deferrer = - [self, aPromiseId, sessionId] () - { - self->RemoveSession(aPromiseId, sessionId.data(), sessionId.size()); - }; - - // If we haven't fully loaded, defer calling this method. - if (MaybeDeferTillInitialized(deferrer)) { - return; - } - - // Check that the SessionManager has not been shutdown before we try and - // resolve any promises. - if (!mHost) { - return; - } - CK_LOGD("ClearKeySessionManager::RemoveSession"); + string sessionId(aSessionId, aSessionId + aSessionIdLength); auto itr = mSessions.find(sessionId); if (itr == mSessions.end()) { CK_LOGW("ClearKey CDM couldn't remove non-existent session."); - - mHost->OnRejectPromise(aPromiseId, - Error::kInvalidAccessError, - 0, - nullptr, - 0); - + mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0); return; } ClearKeySession* session = itr->second; assert(session); string sid = session->Id(); - bool isPersistent = session->Type() == SessionType::kPersistentLicense; + bool isPersistent = session->Type() == kGMPPersistentSession; ClearInMemorySessionData(session); if (!isPersistent) { - mHost->OnResolvePromise(aPromiseId); + mCallback->ResolvePromise(aPromiseId); return; } - mPersistence->PersistentSessionRemoved(sid); + ClearKeyPersistence::PersistentSessionRemoved(sid); + // Overwrite the record storing the sessionId's key data with a zero + // length record to delete it. vector emptyKeydata; - - function resolve = [self, aPromiseId, sessionId] () - { - if (!self->mHost) { - return; - } - self->mHost->OnResolvePromise(aPromiseId); - }; - - function reject = [self, aPromiseId, sessionId] () - { - if (!self->mHost) { - return; - } - static const char* message = "Could not remove session"; - self->mHost->OnRejectPromise(aPromiseId, - Error::kInvalidAccessError, - 0, - message, - strlen(message)); - }; - - WriteData(mHost, sessionId, emptyKeydata, move(resolve), move(reject)); + GMPTask* resolve = WrapTask(mCallback, &GMPDecryptorCallback::ResolvePromise, aPromiseId); + static const char* message = "Could not remove session"; + GMPTask* reject = WrapTask(mCallback, + &GMPDecryptorCallback::RejectPromise, + aPromiseId, + kGMPInvalidAccessError, + message, + strlen(message)); + StoreData(sessionId, emptyKeydata, resolve, reject); } void @@ -609,36 +360,48 @@ ClearKeySessionManager::SetServerCertificate(uint32_t aPromiseId, { // ClearKey CDM doesn't support this method by spec. CK_LOGD("ClearKeySessionManager::SetServerCertificate"); - mHost->OnRejectPromise(aPromiseId, - Error::kNotSupportedError, - 0, - nullptr /* message */, - 0 /* messageLen */); + mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError, + nullptr /* message */, 0 /* messageLen */); } -Status -ClearKeySessionManager::Decrypt(const InputBuffer& aBuffer, - DecryptedBlock* aDecryptedBlock) +void +ClearKeySessionManager::Decrypt(GMPBuffer* aBuffer, + GMPEncryptedBufferMetadata* aMetadata) { CK_LOGD("ClearKeySessionManager::Decrypt"); - CK_LOGARRAY("Key: ", aBuffer.key_id, aBuffer.key_id_size); + if (!mThread) { + CK_LOGW("No decrypt thread"); + mCallback->Decrypted(aBuffer, GMPGenericErr); + return; + } - Buffer* buffer = mHost->Allocate(aBuffer.data_size); - assert(buffer != nullptr); - assert(buffer->Data() != nullptr); - assert(buffer->Capacity() >= aBuffer.data_size); + mThread->Post(WrapTaskRefCounted(this, + &ClearKeySessionManager::DoDecrypt, + aBuffer, aMetadata)); +} - memcpy(buffer->Data(), aBuffer.data, aBuffer.data_size); +void +ClearKeySessionManager::DoDecrypt(GMPBuffer* aBuffer, + GMPEncryptedBufferMetadata* aMetadata) +{ + CK_LOGD("ClearKeySessionManager::DoDecrypt"); - Status status = mDecryptionManager->Decrypt(buffer->Data(), - buffer->Size(), - CryptoMetaData(&aBuffer)); + GMPErr rv = mDecryptionManager->Decrypt(aBuffer->Data(), aBuffer->Size(), + CryptoMetaData(aMetadata)); + CK_LOGD("DeDecrypt finished with code %x\n", rv); + mCallback->Decrypted(aBuffer, rv); +} - aDecryptedBlock->SetDecryptedBuffer(buffer); - aDecryptedBlock->SetTimestamp(aBuffer.timestamp); +void +ClearKeySessionManager::Shutdown() +{ + CK_LOGD("ClearKeySessionManager::Shutdown %p", this); - return status; + for (auto it = mSessions.begin(); it != mSessions.end(); it++) { + delete it->second; + } + mSessions.clear(); } void @@ -646,23 +409,10 @@ ClearKeySessionManager::DecryptingComplete() { CK_LOGD("ClearKeySessionManager::DecryptingComplete %p", this); - for (auto it = mSessions.begin(); it != mSessions.end(); it++) { - delete it->second; - } - mSessions.clear(); + GMPThread* thread = mThread; + thread->Join(); + Shutdown(); mDecryptionManager = nullptr; - mHost = nullptr; - Release(); } - -bool ClearKeySessionManager::MaybeDeferTillInitialized(function aMaybeDefer) -{ - if (mPersistence->IsLoaded()) { - return false; - } - - mDeferredInitialize.emplace(move(aMaybeDefer)); - return true; -} diff --git a/media/gmp-clearkey/0.1/ClearKeySessionManager.h b/media/gmp-clearkey/0.1/ClearKeySessionManager.h index 6dfb84b03748..041b3f036223 100644 --- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h +++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h @@ -1,81 +1,80 @@ /* -* Copyright 2015, Mozilla Foundation and contributors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __ClearKeyDecryptor_h__ #define __ClearKeyDecryptor_h__ -#include "ClearKeyDecryptionManager.h" -#include "ClearKeyPersistence.h" -#include "ClearKeySession.h" -#include "ClearKeyUtils.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" -#include "RefCounted.h" - -#include #include -#include #include #include +#include -class ClearKeySessionManager final : public RefCounted +#include "ClearKeyDecryptionManager.h" +#include "ClearKeySession.h" +#include "ClearKeyUtils.h" +#include "gmp-api/gmp-decryption.h" +#include "RefCounted.h" + +class ClearKeySessionManager final : public GMPDecryptor + , public RefCounted { public: - explicit ClearKeySessionManager(cdm::Host_8* aHost); + ClearKeySessionManager(); - void Init(bool aDistinctiveIdentifierAllowed, - bool aPersistentStateAllowed); + virtual void Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierAllowed, + bool aPersistentStateAllowed) override; - void CreateSession(uint32_t aPromiseId, - cdm::InitDataType aInitDataType, - const uint8_t* aInitData, - uint32_t aInitDataSize, - cdm::SessionType aSessionType); + virtual void CreateSession(uint32_t aCreateSessionToken, + uint32_t aPromiseId, + const char* aInitDataType, + uint32_t aInitDataTypeSize, + const uint8_t* aInitData, + uint32_t aInitDataSize, + GMPSessionType aSessionType) override; - void LoadSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength); + virtual void LoadSession(uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength) override; - void UpdateSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength, - const uint8_t* aResponse, - uint32_t aResponseSize); + virtual void UpdateSession(uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength, + const uint8_t* aResponse, + uint32_t aResponseSize) override; - void CloseSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength); + virtual void CloseSession(uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength) override; - void RemoveSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength); + virtual void RemoveSession(uint32_t aPromiseId, + const char* aSessionId, + uint32_t aSessionIdLength) override; - void SetServerCertificate(uint32_t aPromiseId, - const uint8_t* aServerCert, - uint32_t aServerCertSize); + virtual void SetServerCertificate(uint32_t aPromiseId, + const uint8_t* aServerCert, + uint32_t aServerCertSize) override; - cdm::Status - Decrypt(const cdm::InputBuffer& aBuffer, - cdm::DecryptedBlock* aDecryptedBlock); + virtual void Decrypt(GMPBuffer* aBuffer, + GMPEncryptedBufferMetadata* aMetadata) override; - void DecryptingComplete(); + virtual void DecryptingComplete() override; - void PersistentSessionDataLoaded(uint32_t aPromiseId, + void PersistentSessionDataLoaded(GMPErr aStatus, + uint32_t aPromiseId, const std::string& aSessionId, const uint8_t* aKeyData, uint32_t aKeyDataSize); @@ -83,20 +82,19 @@ public: private: ~ClearKeySessionManager(); + void DoDecrypt(GMPBuffer* aBuffer, GMPEncryptedBufferMetadata* aMetadata); + void Shutdown(); + void ClearInMemorySessionData(ClearKeySession* aSession); - bool MaybeDeferTillInitialized(std::function aMaybeDefer); - void Serialize(const ClearKeySession* aSession, - std::vector& aOutKeyData); + void Serialize(const ClearKeySession* aSession, std::vector& aOutKeyData); RefPtr mDecryptionManager; - RefPtr mPersistence; - cdm::Host_8* mHost = nullptr; + GMPDecryptorCallback* mCallback; + GMPThread* mThread; std::set mKeyIds; std::map mSessions; - - std::queue> mDeferredInitialize; }; #endif // __ClearKeyDecryptor_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp index 03727fd5fedd..0db51c9b7ea1 100644 --- a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp @@ -15,212 +15,180 @@ */ #include "ClearKeyStorage.h" - #include "ClearKeyUtils.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" +#include "gmp-task-utils.h" #include #include "ArrayUtils.h" + #include -using namespace cdm; -using namespace std; - -class WriteRecordClient : public FileIOClient +static GMPErr +RunOnMainThread(GMPTask* aTask) { + return GetPlatform()->runonmainthread(aTask); +} + +GMPErr +OpenRecord(const char* aName, + uint32_t aNameLength, + GMPRecord** aOutRecord, + GMPRecordClient* aClient) +{ + return GetPlatform()->createrecord(aName, aNameLength, aOutRecord, aClient); +} + +class WriteRecordClient : public GMPRecordClient { public: /* * This function will take the memory ownership of the parameters and * delete them when done. */ - static void Write(Host_8* aHost, - string& aRecordName, - const vector& aData, - function&& aOnSuccess, - function&& aOnFailure) -{ - WriteRecordClient* client = new WriteRecordClient(aData, - move(aOnSuccess), - move(aOnFailure)); - client->Do(aRecordName, aHost); + static void Write(const std::string& aRecordName, + const std::vector& aData, + GMPTask* aOnSuccess, + GMPTask* aOnFailure) { + (new WriteRecordClient(aData, aOnSuccess, aOnFailure))->Do(aRecordName); } - void OnOpenComplete(Status aStatus) override - { - // If we hit an error, fail. - if (aStatus != Status::kSuccess) { - Done(aStatus); - } else if (mFileIO) { // Otherwise, write our data to the file. - mFileIO->Write(&mData[0], mData.size()); + virtual void OpenComplete(GMPErr aStatus) override { + if (GMP_FAILED(aStatus) || + GMP_FAILED(mRecord->Write(&mData.front(), mData.size()))) { + Done(mOnFailure, mOnSuccess); } } - void OnReadComplete(Status aStatus, - const uint8_t* aData, - uint32_t aDataSize) override - { - // This function should never be called, we only ever write data with this - // client. - assert(false); + virtual void ReadComplete(GMPErr aStatus, + const uint8_t* aData, + uint32_t aDataSize) override { + assert(false); // Should not reach here. } - void OnWriteComplete(Status aStatus) override - { - Done(aStatus); + virtual void WriteComplete(GMPErr aStatus) override { + if (GMP_FAILED(aStatus)) { + Done(mOnFailure, mOnSuccess); + } else { + Done(mOnSuccess, mOnFailure); + } } private: - explicit WriteRecordClient(const vector& aData, - function&& aOnSuccess, - function&& aOnFailure) - : mFileIO(nullptr) - , mOnSuccess(move(aOnSuccess)) - , mOnFailure(move(aOnFailure)) + WriteRecordClient(const std::vector& aData, + GMPTask* aOnSuccess, + GMPTask* aOnFailure) + : mRecord(nullptr) + , mOnSuccess(aOnSuccess) + , mOnFailure(aOnFailure) , mData(aData) {} - void Do(const string& aName, Host_8* aHost) - { - // Initialize the FileIO. - mFileIO = aHost->CreateFileIO(this); - mFileIO->Open(aName.c_str(), aName.size()); + void Do(const std::string& aName) { + auto err = OpenRecord(aName.c_str(), aName.size(), &mRecord, this); + if (GMP_FAILED(err) || + GMP_FAILED(mRecord->Open())) { + Done(mOnFailure, mOnSuccess); + } } - void Done(cdm::FileIOClient::Status aStatus) - { + void Done(GMPTask* aToRun, GMPTask* aToDestroy) { // Note: Call Close() before running continuation, in case the // continuation tries to open the same record; if we call Close() // after running the continuation, the Close() call will arrive // just after the Open() call succeeds, immediately closing the // record we just opened. - if (mFileIO) { - mFileIO->Close(); + if (mRecord) { + mRecord->Close(); } - - if (IO_SUCCEEDED(aStatus)) { - mOnSuccess(); - } else { - mOnFailure(); - } - + aToDestroy->Destroy(); + RunOnMainThread(aToRun); delete this; } - FileIO* mFileIO = nullptr; - - function mOnSuccess; - function mOnFailure; - - const vector mData; + GMPRecord* mRecord; + GMPTask* mOnSuccess; + GMPTask* mOnFailure; + const std::vector mData; }; void -WriteData(Host_8* aHost, - string& aRecordName, - const vector& aData, - function&& aOnSuccess, - function&& aOnFailure) +StoreData(const std::string& aRecordName, + const std::vector& aData, + GMPTask* aOnSuccess, + GMPTask* aOnFailure) { - WriteRecordClient::Write(aHost, - aRecordName, - aData, - move(aOnSuccess), - move(aOnFailure)); + WriteRecordClient::Write(aRecordName, aData, aOnSuccess, aOnFailure); } -class ReadRecordClient : public FileIOClient -{ +class ReadRecordClient : public GMPRecordClient { public: /* * This function will take the memory ownership of the parameters and * delete them when done. */ - static void Read(Host_8* aHost, - string& aRecordName, - function&& aOnSuccess, - function&& aOnFailure) - { - - (new ReadRecordClient(move(aOnSuccess), move(aOnFailure)))-> - Do(aRecordName, aHost); + static void Read(const std::string& aRecordName, + ReadContinuation* aContinuation) { + assert(aContinuation); + (new ReadRecordClient(aContinuation))->Do(aRecordName); } - void OnOpenComplete(Status aStatus) override - { + virtual void OpenComplete(GMPErr aStatus) override { auto err = aStatus; - if (aStatus != Status::kSuccess) { + if (GMP_FAILED(err) || + GMP_FAILED(err = mRecord->Read())) { Done(err, nullptr, 0); - } else { - mFileIO->Read(); } } - void OnReadComplete(Status aStatus, - const uint8_t* aData, - uint32_t aDataSize) override - { + virtual void ReadComplete(GMPErr aStatus, + const uint8_t* aData, + uint32_t aDataSize) override { Done(aStatus, aData, aDataSize); } - void OnWriteComplete(Status aStatus) override - { - // We should never reach here, this client only ever reads data. - assert(false); + virtual void WriteComplete(GMPErr aStatus) override { + assert(false); // Should not reach here. } private: - explicit ReadRecordClient(function&& aOnSuccess, - function&& aOnFailure) - : mFileIO(nullptr) - , mOnSuccess(move(aOnSuccess)) - , mOnFailure(move(aOnFailure)) - {} + explicit ReadRecordClient(ReadContinuation* aContinuation) + : mRecord(nullptr) + , mContinuation(aContinuation) {} - void Do(const string& aName, Host_8* aHost) - { - mFileIO = aHost->CreateFileIO(this); - mFileIO->Open(aName.c_str(), aName.size()); + void Do(const std::string& aName) { + auto err = OpenRecord(aName.c_str(), aName.size(), &mRecord, this); + if (GMP_FAILED(err) || + GMP_FAILED(err = mRecord->Open())) { + Done(err, nullptr, 0); + } } - void Done(cdm::FileIOClient::Status aStatus, - const uint8_t* aData, - uint32_t aDataSize) - { + void Done(GMPErr err, const uint8_t* aData, uint32_t aDataSize) { // Note: Call Close() before running continuation, in case the // continuation tries to open the same record; if we call Close() // after running the continuation, the Close() call will arrive // just after the Open() call succeeds, immediately closing the // record we just opened. - if (mFileIO) { - mFileIO->Close(); + if (mRecord) { + mRecord->Close(); } - - if (IO_SUCCEEDED(aStatus)) { - mOnSuccess(aData, aDataSize); - } else { - mOnFailure(); - } - + mContinuation->ReadComplete(err, aData, aDataSize); + delete mContinuation; delete this; } - FileIO* mFileIO = nullptr; - - function mOnSuccess; - function mOnFailure; + GMPRecord* mRecord; + ReadContinuation* mContinuation; }; void -ReadData(Host_8* mHost, - string& aRecordName, - function&& aOnSuccess, - function&& aOnFailure) +ReadData(const std::string& aRecordName, + ReadContinuation* aContinuation) { - ReadRecordClient::Read(mHost, - aRecordName, - move(aOnSuccess), - move(aOnFailure)); + ReadRecordClient::Read(aRecordName, aContinuation); +} + +GMPErr +EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc) +{ + return GetPlatform()->getrecordenumerator(aRecvIteratorFunc, nullptr); } diff --git a/media/gmp-clearkey/0.1/ClearKeyStorage.h b/media/gmp-clearkey/0.1/ClearKeyStorage.h index 2844e4be7797..695f67d9eaad 100644 --- a/media/gmp-clearkey/0.1/ClearKeyStorage.h +++ b/media/gmp-clearkey/0.1/ClearKeyStorage.h @@ -17,27 +17,32 @@ #ifndef __ClearKeyStorage_h__ #define __ClearKeyStorage_h__ -#include -#include +#include "gmp-api/gmp-errors.h" +#include "gmp-api/gmp-platform.h" #include #include +#include -#include "ClearKeySessionManager.h" +class GMPTask; -#define IO_SUCCEEDED(x) ((x) == cdm::FileIOClient::Status::kSuccess) -#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_8* aHost, - std::string& aRecordName, +// Responsible for ensuring that both aOnSuccess and aOnFailure are destroyed. +void StoreData(const std::string& aRecordName, const std::vector& aData, - std::function&& aOnSuccess, - std::function&& aOnFailure); + GMPTask* aOnSuccess, + GMPTask* aOnFailure); -// Reads data from a file and fires the appropriate callback when complete. -void ReadData(cdm::Host_8* aHost, - std::string& aRecordName, - std::function&& aOnSuccess, - std::function&& aOnFailure); +class ReadContinuation { +public: + virtual void ReadComplete(GMPErr aStatus, + const uint8_t* aData, + uint32_t aLength) = 0; + virtual ~ReadContinuation() {} +}; + +// Deletes aContinuation after running it to report the result. +void ReadData(const std::string& aSessionId, + ReadContinuation* aContinuation); + +GMPErr EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc); #endif // __ClearKeyStorage_h__ diff --git a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp index 0ed47671645d..b99a50a4dc72 100644 --- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp @@ -14,77 +14,33 @@ * limitations under the License. */ -#include "ClearKeyUtils.h" - #include -#include -#include -#include #include -#include -#include #include #include -#include #include -#include "ArrayUtils.h" -#include "BigEndian.h" +#include "ClearKeyUtils.h" #include "ClearKeyBase64.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" +#include "ArrayUtils.h" +#include +#include +#include "BigEndian.h" #include "openaes/oaes_lib.h" -#include "psshparser/PsshParser.h" -using namespace cdm; using namespace std; void CK_Log(const char* aFmt, ...) { - FILE* out = stdout; - - if (getenv("CLEARKEY_LOG_FILE")) { - out = fopen(getenv("CLEARKEY_LOG_FILE"), "a"); - } - va_list ap; va_start(ap, aFmt); - const size_t len = 1024; - char buf[len]; - vsnprintf(buf, len, aFmt, ap); + vprintf(aFmt, ap); va_end(ap); - fprintf(out, "%s\n", buf); - fflush(out); - - if (out != stdout) { - fclose(out); - } -} - -static bool -PrintableAsString(const uint8_t* aBytes, uint32_t aLength) -{ - return all_of(aBytes, aBytes + aLength, [] (uint8_t c) { - return isprint(c) == 1; - }); -} - -void -CK_LogArray(const char* prepend, - const uint8_t* aData, - const uint32_t aDataSize) -{ - // If the data is valid ascii, use that. Otherwise print the hex - string data = PrintableAsString(aData, aDataSize) ? - string(aData, aData + aDataSize) : - ClearKeyUtils::ToHexString(aData, aDataSize); - - CK_LOGD("%s%s", prepend, data.c_str()); + printf("\n"); + fflush(stdout); } static void @@ -159,9 +115,7 @@ EncodeBase64Web(vector aBinary, string& aEncoded) // Cast idx to size_t before using it as an array-index, // to pacify clang 'Wchar-subscripts' warning: size_t idx = static_cast(out[i]); - - // out of bounds index for 'sAlphabet' - assert(idx < MOZ_ARRAY_LENGTH(sAlphabet)); + assert(idx < MOZ_ARRAY_LENGTH(sAlphabet)); // out of bounds index for 'sAlphabet' out[i] = sAlphabet[idx]; } @@ -171,7 +125,7 @@ EncodeBase64Web(vector aBinary, string& aEncoded) /* static */ void ClearKeyUtils::MakeKeyRequest(const vector& aKeyIDs, string& aOutRequest, - SessionType aSessionType) + GMPSessionType aSessionType) { assert(aKeyIDs.size() && aOutRequest.empty()); @@ -435,7 +389,7 @@ ParseKeys(ParserContext& aCtx, vector& aOutKeys) /* static */ bool ClearKeyUtils::ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize, vector& aOutKeys, - SessionType aSessionType) + GMPSessionType aSessionType) { ParserContext ctx; ctx.mIter = aKeyData; @@ -551,16 +505,15 @@ ClearKeyUtils::ParseKeyIdsInitData(const uint8_t* aInitData, } /* static */ const char* -ClearKeyUtils::SessionTypeToString(SessionType aSessionType) +ClearKeyUtils::SessionTypeToString(GMPSessionType aSessionType) { switch (aSessionType) { - case SessionType::kTemporary: return "temporary"; - case SessionType::kPersistentLicense: return "persistent-license"; - default: { - // We don't support any other license types. - assert(false); - return "invalid"; - } + case kGMPTemporySession: return "temporary"; + case kGMPPersistentSession: return "persistent-license"; + default: { + assert(false); // Should not reach here. + return "invalid"; + } } } @@ -580,15 +533,9 @@ ClearKeyUtils::IsValidSessionId(const char* aBuff, uint32_t aLength) return true; } -string -ClearKeyUtils::ToHexString(const uint8_t * aBytes, uint32_t aLength) -{ - stringstream ss; - ss << std::showbase << std::uppercase << std::hex; - for (uint32_t i = 0; i < aLength; ++i) { - ss << std::hex << static_cast(aBytes[i]); - ss << " "; - } - - return ss.str(); +GMPMutex* GMPCreateMutex() { + GMPMutex* mutex; + auto err = GetPlatform()->createmutex(&mutex); + assert(mutex); + return GMP_FAILED(err) ? nullptr : mutex; } diff --git a/media/gmp-clearkey/0.1/ClearKeyUtils.h b/media/gmp-clearkey/0.1/ClearKeyUtils.h index 1d4a293d94ec..fc29b9211990 100644 --- a/media/gmp-clearkey/0.1/ClearKeyUtils.h +++ b/media/gmp-clearkey/0.1/ClearKeyUtils.h @@ -21,29 +21,22 @@ #include #include #include - -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" +#include "gmp-api/gmp-decryption.h" #if 0 void CK_Log(const char* aFmt, ...); #define CK_LOGE(...) CK_Log(__VA_ARGS__) #define CK_LOGD(...) CK_Log(__VA_ARGS__) #define CK_LOGW(...) CK_Log(__VA_ARGS__) -#define CK_LOGARRAY(APREPEND, ADATA, ADATA_SIZE) CK_LogArray(APREPEND, \ - ADATA, \ - ADATA_SIZE) #else -// Note: Enabling logging slows things down a LOT, especially when logging to -// a file. #define CK_LOGE(...) #define CK_LOGD(...) #define CK_LOGW(...) -#define CK_LOGARRAY(APREPEND, ADATA, ADATA_SIZE) #endif +struct GMPPlatformAPI; +extern GMPPlatformAPI* GetPlatform(); + typedef std::vector KeyId; typedef std::vector Key; @@ -55,10 +48,6 @@ static const uint32_t kMaxSessionResponseLength = 65536; static const uint32_t kMaxWebmInitDataSize = 65536; static const uint32_t kMaxKeyIdsLength = 512; -void CK_LogArray(const char* aPrepend, - const uint8_t* aData, - const uint32_t aDataSize); - struct KeyIdPair { KeyId mKeyId; @@ -77,16 +66,14 @@ public: static void MakeKeyRequest(const std::vector& aKeyIds, std::string& aOutRequest, - cdm::SessionType aSessionType); + GMPSessionType aSessionType); static bool ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize, std::vector& aOutKeys, - cdm::SessionType aSessionType); - static const char* SessionTypeToString(cdm::SessionType aSessionType); + GMPSessionType aSessionType); + static const char* SessionTypeToString(GMPSessionType aSessionType); static bool IsValidSessionId(const char* aBuff, uint32_t aLength); - - static std::string ToHexString(const uint8_t * aBytes, uint32_t aLength); }; template @@ -96,6 +83,27 @@ Contains(const Container& aContainer, const Element& aElement) return aContainer.find(aElement) != aContainer.end(); } +class AutoLock { +public: + explicit AutoLock(GMPMutex* aMutex) + : mMutex(aMutex) + { + assert(aMutex); + if (mMutex) { + mMutex->Acquire(); + } + } + ~AutoLock() { + if (mMutex) { + mMutex->Release(); + } + } +private: + GMPMutex* mMutex; +}; + +GMPMutex* GMPCreateMutex(); + template inline void Assign(std::vector& aVec, const T* aData, size_t aLength) diff --git a/media/gmp-clearkey/0.1/RefCounted.h b/media/gmp-clearkey/0.1/RefCounted.h index b3a7c7849d48..6da694295864 100644 --- a/media/gmp-clearkey/0.1/RefCounted.h +++ b/media/gmp-clearkey/0.1/RefCounted.h @@ -21,7 +21,41 @@ #include #include "ClearKeyUtils.h" +#if defined(_MSC_VER) #include +typedef std::atomic AtomicRefCount; +#else +class AtomicRefCount { +public: + explicit AtomicRefCount(uint32_t aValue) + : mCount(aValue) + , mMutex(GMPCreateMutex()) + { + assert(mMutex); + } + ~AtomicRefCount() + { + if (mMutex) { + mMutex->Destroy(); + } + } + uint32_t operator--() { + AutoLock lock(mMutex); + return --mCount; + } + uint32_t operator++() { + AutoLock lock(mMutex); + return ++mCount; + } + operator uint32_t() { + AutoLock lock(mMutex); + return mCount; + } +private: + uint32_t mCount; + GMPMutex* mMutex; +}; +#endif // Note: Thread safe. class RefCounted { @@ -47,41 +81,27 @@ protected: { assert(!mRefCount); } - std::atomic mRefCount; + AtomicRefCount mRefCount; }; template class RefPtr { public: - RefPtr(const RefPtr& src) { - Set(src.mPtr); + explicit RefPtr(T* aPtr) : mPtr(nullptr) { + Assign(aPtr); } - - explicit RefPtr(T* aPtr) { - Set(aPtr); - } - RefPtr() { Set(nullptr); } - ~RefPtr() { - Set(nullptr); + Assign(nullptr); } T* operator->() const { return mPtr; } - T** operator&() { return &mPtr; } - T* operator->() { return mPtr; } - operator T*() { return mPtr; } - - T* Get() const { return mPtr; } RefPtr& operator=(T* aVal) { - Set(aVal); + Assign(aVal); return *this; } private: - T* Set(T* aPtr) { - if (mPtr == aPtr) { - return aPtr; - } + void Assign(T* aPtr) { if (mPtr) { mPtr->Release(); } @@ -89,10 +109,8 @@ private: if (mPtr) { aPtr->AddRef(); } - return mPtr; } - - T* mPtr = nullptr; + T* mPtr; }; #endif // __RefCount_h__ diff --git a/media/gmp-clearkey/0.1/VideoDecoder.cpp b/media/gmp-clearkey/0.1/VideoDecoder.cpp index 27382dd0bea7..a3f25402b158 100644 --- a/media/gmp-clearkey/0.1/VideoDecoder.cpp +++ b/media/gmp-clearkey/0.1/VideoDecoder.cpp @@ -14,162 +14,247 @@ * limitations under the License. */ -#include #include #include +#include "AnnexB.h" #include "BigEndian.h" #include "ClearKeyDecryptionManager.h" #include "ClearKeyUtils.h" +#include "gmp-task-utils.h" #include "VideoDecoder.h" using namespace wmf; -using namespace cdm; -VideoDecoder::VideoDecoder(Host_8 *aHost) - : mHost(aHost) +VideoDecoder::VideoDecoder(GMPVideoHost *aHostAPI) + : mHostAPI(aHostAPI) + , mCallback(nullptr) + , mWorkerThread(nullptr) + , mMutex(nullptr) + , mNumInputTasks(0) + , mSentExtraData(false) + , mIsFlushing(false) , mHasShutdown(false) { // We drop the ref in DecodingComplete(). AddRef(); - - mDecoder = new WMFH264Decoder(); - - uint32_t cores = std::max(1u, std::thread::hardware_concurrency()); - HRESULT hr = mDecoder->Init(cores); } VideoDecoder::~VideoDecoder() { - + if (mMutex) { + mMutex->Destroy(); + } } -Status -VideoDecoder::InitDecode(const VideoDecoderConfig& aConfig) +void +VideoDecoder::InitDecode(const GMPVideoCodec& aCodecSettings, + const uint8_t* aCodecSpecific, + uint32_t aCodecSpecificLength, + GMPVideoDecoderCallback* aCallback, + int32_t aCoreCount) { - if (!mDecoder) { + mCallback = aCallback; + assert(mCallback); + mDecoder = new WMFH264Decoder(); + HRESULT hr = mDecoder->Init(aCoreCount); + if (FAILED(hr)) { CK_LOGD("VideoDecoder::InitDecode failed to init WMFH264Decoder"); - - return Status::kDecodeError; + mCallback->Error(GMPGenericErr); + return; } - return Status::kSuccess; + auto err = GetPlatform()->createmutex(&mMutex); + if (GMP_FAILED(err)) { + CK_LOGD("VideoDecoder::InitDecode failed to create GMPMutex"); + mCallback->Error(GMPGenericErr); + return; + } + + // The first byte is mPacketizationMode, which is only relevant for + // WebRTC/OpenH264 usecase. + const uint8_t* avcc = aCodecSpecific + 1; + const uint8_t* avccEnd = aCodecSpecific + aCodecSpecificLength; + mExtraData.insert(mExtraData.end(), avcc, avccEnd); + + AnnexB::ConvertConfig(mExtraData, mAnnexB); } -Status -VideoDecoder::Decode(const InputBuffer& aInputBuffer, VideoFrame* aVideoFrame) +void +VideoDecoder::EnsureWorker() { - // If the input buffer we have been passed has a null buffer, it means we - // should drain. - if (!aInputBuffer.data) { - // This will drain the decoder until there are no frames left to drain, - // whereupon it will return 'NeedsMoreData'. - CK_LOGD("Input buffer null: Draining"); - return Drain(aVideoFrame); + if (!mWorkerThread) { + GetPlatform()->createthread(&mWorkerThread); + if (!mWorkerThread) { + mCallback->Error(GMPAllocErr); + return; + } + } +} + +void +VideoDecoder::Decode(GMPVideoEncodedFrame* aInputFrame, + bool aMissingFrames, + const uint8_t* aCodecSpecificInfo, + uint32_t aCodecSpecificInfoLength, + int64_t aRenderTimeMs) +{ + if (aInputFrame->BufferType() != GMP_BufferLength32) { + // Gecko should only send frames with 4 byte NAL sizes to GMPs. + mCallback->Error(GMPGenericErr); + return; } - DecodeData* data = new DecodeData(); - Assign(data->mBuffer, aInputBuffer.data, aInputBuffer.data_size); - data->mTimestamp = aInputBuffer.timestamp; - data->mCrypto = CryptoMetaData(&aInputBuffer); + EnsureWorker(); + { + AutoLock lock(mMutex); + mNumInputTasks++; + } + + // Note: we don't need the codec specific info on a per-frame basis. + // It's mostly useful for WebRTC use cases. + + // Make a copy of the data, so we can release aInputFrame ASAP, + // to avoid too many shmem handles being held by the GMP process. + // If the GMP process holds on to too many shmem handles, the Gecko + // side can fail to allocate a shmem to send more input. This is + // particularly a problem in Gecko mochitests, which can open multiple + // actors at once which share the same pool of shmems. + DecodeData* data = new DecodeData(); + Assign(data->mBuffer, aInputFrame->Buffer(), aInputFrame->Size()); + data->mTimestamp = aInputFrame->TimeStamp(); + data->mDuration = aInputFrame->Duration(); + data->mIsKeyframe = (aInputFrame->FrameType() == kGMPKeyFrame); + const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData(); + if (crypto) { + data->mCrypto.Init(crypto); + } + aInputFrame->Destroy(); + mWorkerThread->Post(WrapTaskRefCounted(this, + &VideoDecoder::DecodeTask, + data)); +} + +void +VideoDecoder::DecodeTask(DecodeData* aData) +{ CK_LOGD("VideoDecoder::DecodeTask"); - AutoPtr d(data); + AutoPtr d(aData); HRESULT hr; - if (!data || !mDecoder) { - CK_LOGE("Decode job not set up correctly!"); - return Status::kDecodeError; + { + AutoLock lock(mMutex); + mNumInputTasks--; + assert(mNumInputTasks >= 0); } - std::vector& buffer = data->mBuffer; + if (mIsFlushing) { + CK_LOGD("VideoDecoder::DecodeTask rejecting frame: flushing."); + return; + } - if (data->mCrypto.IsValid()) { - Status rv = - ClearKeyDecryptionManager::Get()->Decrypt(buffer, data->mCrypto); + if (!aData || !mHostAPI || !mDecoder) { + CK_LOGE("Decode job not set up correctly!"); + return; + } - if (STATUS_FAILED(rv)) { - CK_LOGARRAY("Failed to decrypt video using key ", - aInputBuffer.key_id, - aInputBuffer.key_id_size); - return rv; + std::vector& buffer = aData->mBuffer; + if (aData->mCrypto.IsValid()) { + // Plugin host should have set up its decryptor/key sessions + // before trying to decode! + GMPErr rv = + ClearKeyDecryptionManager::Get()->Decrypt(buffer, aData->mCrypto); + + if (GMP_FAILED(rv)) { + MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::Error, rv)); + return; } } + AnnexB::ConvertFrameInPlace(buffer); + + if (aData->mIsKeyframe) { + // We must send the SPS and PPS to Windows Media Foundation's decoder. + // Note: We do this *after* decryption, otherwise the subsample info + // would be incorrect. + buffer.insert(buffer.begin(), mAnnexB.begin(), mAnnexB.end()); + } + hr = mDecoder->Input(buffer.data(), buffer.size(), - data->mTimestamp); + aData->mTimestamp, + aData->mDuration); CK_LOGD("VideoDecoder::DecodeTask() Input ret hr=0x%x\n", hr); - - if (FAILED(hr)) { - assert(hr != MF_E_TRANSFORM_NEED_MORE_INPUT); - CK_LOGE("VideoDecoder::DecodeTask() decode failed ret=0x%x%s\n", - hr, - ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : "")); - CK_LOGD("Decode failed. The decoder is not accepting input"); - return Status::kDecodeError; + hr, + ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : "")); + return; } - return OutputFrame(aVideoFrame); -} - -Status VideoDecoder::OutputFrame(VideoFrame* aVideoFrame) { - HRESULT hr = S_OK; - - // Read all the output from the decoder. Ideally, this would be a while loop - // where we read the output and check the result as the condition. However, - // this produces a memory leak connected to assigning a new CComPtr to the - // address of the old one, which avoids the CComPtr cleaning up. - while (true) { + while (hr == S_OK) { CComPtr output; hr = mDecoder->Output(&output); - - if (hr != S_OK) { - break; - } - CK_LOGD("VideoDecoder::DecodeTask() output ret=0x%x\n", hr); + if (hr == S_OK) { + MaybeRunOnMainThread( + WrapTaskRefCounted(this, + &VideoDecoder::ReturnOutput, + CComPtr(output), + mDecoder->GetFrameWidth(), + mDecoder->GetFrameHeight(), + mDecoder->GetStride())); + } + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { + AutoLock lock(mMutex); + if (mNumInputTasks == 0) { + // We have run all input tasks. We *must* notify Gecko so that it will + // send us more data. + MaybeRunOnMainThread( + WrapTask(mCallback, + &GMPVideoDecoderCallback::InputDataExhausted)); + } + } + if (FAILED(hr)) { + CK_LOGE("VideoDecoder::DecodeTask() output failed hr=0x%x\n", hr); + } + } +} - mOutputQueue.push(output); - CK_LOGD("Queue size: %u", mOutputQueue.size()); +void +VideoDecoder::ReturnOutput(IMFSample* aSample, + int32_t aWidth, + int32_t aHeight, + int32_t aStride) +{ + CK_LOGD("[%p] VideoDecoder::ReturnOutput()\n", this); + assert(aSample); + + HRESULT hr; + + GMPVideoFrame* f = nullptr; + auto err = mHostAPI->CreateFrame(kGMPI420VideoFrame, &f); + if (GMP_FAILED(err) || !f) { + CK_LOGE("Failed to create i420 frame!\n"); + return; + } + if (HasShutdown()) { + // Note: GMPVideoHost::CreateFrame() can process messages before returning, + // including a message that calls VideoDecoder::DecodingComplete(), i.e. + // we can shutdown during the call! + CK_LOGD("Shutdown while waiting on GMPVideoHost::CreateFrame()!\n"); + f->Destroy(); + return; } - // If we don't have any inputs, we need more data. - if (mOutputQueue.empty()) { - CK_LOGD("Decode failed. Not enought data; Requesting more input"); - return Status::kNeedMoreData; - } + auto vf = static_cast(f); - // We will get a MF_E_TRANSFORM_NEED_MORE_INPUT every time, as we always - // consume everything in the buffer. - if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT && FAILED(hr)) { - CK_LOGD("Decode failed output ret=0x%x\n", hr); - return Status::kDecodeError; - } + hr = SampleToVideoFrame(aSample, aWidth, aHeight, aStride, vf); + ENSURE(SUCCEEDED(hr), /*void*/); - CComPtr result = mOutputQueue.front(); - mOutputQueue.pop(); - - // The Chromium CDM API doesn't have support for negative strides, though - // they are theoretically possible in real world data. - if (mDecoder->GetStride() <= 0) { - return Status::kDecodeError; - } - - hr = SampleToVideoFrame(result, - mDecoder->GetFrameWidth(), - mDecoder->GetFrameHeight(), - mDecoder->GetStride(), - aVideoFrame); - if (FAILED(hr)) { - return Status::kDecodeError; - } - - CK_LOGD("Decode succeeded."); - return Status::kSuccess; + mCallback->Decoded(vf); } HRESULT @@ -177,19 +262,14 @@ VideoDecoder::SampleToVideoFrame(IMFSample* aSample, int32_t aWidth, int32_t aHeight, int32_t aStride, - VideoFrame* aVideoFrame) + GMPVideoi420Frame* aVideoFrame) { - CK_LOGD("[%p] VideoDecoder::SampleToVideoFrame()\n", this); - assert(aSample); - ENSURE(aSample != nullptr, E_POINTER); ENSURE(aVideoFrame != nullptr, E_POINTER); HRESULT hr; CComPtr mediaBuffer; - aVideoFrame->SetFormat(kI420); - // Must convert to contiguous mediaBuffer to use IMD2DBuffer interface. hr = aSample->ConvertToContiguousBuffer(&mediaBuffer); ENSURE(SUCCEEDED(hr), hr); @@ -205,60 +285,46 @@ VideoDecoder::SampleToVideoFrame(IMFSample* aSample, hr = twoDBuffer->Lock2D(&data, &stride); ENSURE(SUCCEEDED(hr), hr); } else { - hr = mediaBuffer->Lock(&data, nullptr, nullptr); + hr = mediaBuffer->Lock(&data, NULL, NULL); ENSURE(SUCCEEDED(hr), hr); stride = aStride; } - // The U and V planes are stored 16-row-aligned, so we need to add padding + // The V and U planes are stored 16-row-aligned, so we need to add padding // to the row heights to ensure the Y'CbCr planes are referenced properly. - // YV12, planar format: [YYYY....][UUUU....][VVVV....] - // i.e., Y, then U, then V. + // YV12, planar format: [YYYY....][VVVV....][UUUU....] + // i.e., Y, then V, then U. uint32_t padding = 0; if (aHeight % 16 != 0) { padding = 16 - (aHeight % 16); } - uint32_t ySize = stride * (aHeight + padding); - uint32_t uSize = stride * (aHeight + padding) / 4; - uint32_t halfStride = (stride + 1) / 2; - uint32_t halfHeight = (aHeight + 1) / 2; + int32_t y_size = stride * (aHeight + padding); + int32_t v_size = stride * (aHeight + padding) / 4; + int32_t halfStride = (stride + 1) / 2; + int32_t halfHeight = (aHeight + 1) / 2; - aVideoFrame->SetStride(VideoFrame::kYPlane, stride); - aVideoFrame->SetStride(VideoFrame::kUPlane, halfStride); - aVideoFrame->SetStride(VideoFrame::kVPlane, halfStride); + auto err = aVideoFrame->CreateEmptyFrame(stride, aHeight, stride, halfStride, halfStride); + ENSURE(GMP_SUCCEEDED(err), E_FAIL); - aVideoFrame->SetSize(Size(aWidth, aHeight)); + err = aVideoFrame->SetWidth(aWidth); + ENSURE(GMP_SUCCEEDED(err), E_FAIL); + err = aVideoFrame->SetHeight(aHeight); + ENSURE(GMP_SUCCEEDED(err), E_FAIL); - uint64_t bufferSize = ySize + 2 * uSize; + uint8_t* outBuffer = aVideoFrame->Buffer(kGMPYPlane); + ENSURE(outBuffer != nullptr, E_FAIL); + assert(aVideoFrame->AllocatedSize(kGMPYPlane) >= stride*aHeight); + memcpy(outBuffer, data, stride*aHeight); - // If the buffer is bigger than the max for a 32 bit, fail to avoid buffer - // overflows. - if (bufferSize > UINT32_MAX) { - return Status::kDecodeError; - } + outBuffer = aVideoFrame->Buffer(kGMPUPlane); + ENSURE(outBuffer != nullptr, E_FAIL); + assert(aVideoFrame->AllocatedSize(kGMPUPlane) >= halfStride*halfHeight); + memcpy(outBuffer, data+y_size, halfStride*halfHeight); - // Get the buffer from the host. - Buffer* buffer = mHost->Allocate(bufferSize); - aVideoFrame->SetFrameBuffer(buffer); - - // Make sure the buffer is non-null (allocate guarantees it will be of - // sufficient size). - if (!buffer) { - return E_OUTOFMEMORY; - } - - uint8_t* outBuffer = buffer->Data(); - - aVideoFrame->SetPlaneOffset(VideoFrame::kYPlane, 0); - - // Offset is the size of the copied y data. - aVideoFrame->SetPlaneOffset(VideoFrame::kUPlane, ySize); - - // Offset is the size of the copied y data + the size of the copied u data. - aVideoFrame->SetPlaneOffset(VideoFrame::kVPlane, ySize + uSize); - - // Copy the data. - memcpy(outBuffer, data, ySize + uSize * 2); + outBuffer = aVideoFrame->Buffer(kGMPVPlane); + ENSURE(outBuffer != nullptr, E_FAIL); + assert(aVideoFrame->AllocatedSize(kGMPVPlane) >= halfStride*halfHeight); + memcpy(outBuffer, data + y_size + v_size, halfStride*halfHeight); if (twoDBuffer) { twoDBuffer->Unlock2D(); @@ -269,46 +335,84 @@ VideoDecoder::SampleToVideoFrame(IMFSample* aSample, LONGLONG hns = 0; hr = aSample->GetSampleTime(&hns); ENSURE(SUCCEEDED(hr), hr); - aVideoFrame->SetTimestamp(HNsToUsecs(hns)); + hr = aSample->GetSampleDuration(&hns); + ENSURE(SUCCEEDED(hr), hr); + aVideoFrame->SetDuration(HNsToUsecs(hns)); + return S_OK; } +void +VideoDecoder::ResetCompleteTask() +{ + mIsFlushing = false; + if (mCallback) { + MaybeRunOnMainThread(WrapTask(mCallback, + &GMPVideoDecoderCallback::ResetComplete)); + } +} + void VideoDecoder::Reset() { - CK_LOGD("VideoDecoder::Reset"); - + mIsFlushing = true; if (mDecoder) { mDecoder->Reset(); } - // Remove all the frames from the output queue. - while (!mOutputQueue.empty()) { - mOutputQueue.pop(); - } + // Schedule ResetComplete callback to run after existing frames have been + // flushed out of the task queue. + EnsureWorker(); + mWorkerThread->Post(WrapTaskRefCounted(this, + &VideoDecoder::ResetCompleteTask)); } -Status -VideoDecoder::Drain(VideoFrame* aVideoFrame) +void +VideoDecoder::DrainTask() { - CK_LOGD("VideoDecoder::Drain()"); - - if (!mDecoder) { - CK_LOGD("Drain failed! Decoder was not initialized"); - return Status::kDecodeError; - } - mDecoder->Drain(); // Return any pending output. - return OutputFrame(aVideoFrame); + HRESULT hr = S_OK; + while (hr == S_OK) { + CComPtr output; + hr = mDecoder->Output(&output); + CK_LOGD("VideoDecoder::DrainTask() output ret=0x%x\n", hr); + if (hr == S_OK) { + MaybeRunOnMainThread( + WrapTaskRefCounted(this, + &VideoDecoder::ReturnOutput, + CComPtr(output), + mDecoder->GetFrameWidth(), + mDecoder->GetFrameHeight(), + mDecoder->GetStride())); + } + } + MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::DrainComplete)); +} + +void +VideoDecoder::Drain() +{ + if (!mDecoder) { + if (mCallback) { + mCallback->DrainComplete(); + } + return; + } + EnsureWorker(); + mWorkerThread->Post(WrapTaskRefCounted(this, + &VideoDecoder::DrainTask)); } void VideoDecoder::DecodingComplete() { + if (mWorkerThread) { + mWorkerThread->Join(); + } mHasShutdown = true; // Release the reference we added in the constructor. There may be @@ -316,3 +420,36 @@ VideoDecoder::DecodingComplete() // us alive a little longer. Release(); } + +void +VideoDecoder::MaybeRunOnMainThread(GMPTask* aTask) +{ + class MaybeRunTask : public GMPTask + { + public: + MaybeRunTask(VideoDecoder* aDecoder, GMPTask* aTask) + : mDecoder(aDecoder), mTask(aTask) + { } + + virtual void Run(void) { + if (mDecoder->HasShutdown()) { + CK_LOGD("Trying to dispatch to main thread after VideoDecoder has shut down"); + return; + } + + mTask->Run(); + } + + virtual void Destroy() + { + mTask->Destroy(); + delete this; + } + + private: + RefPtr mDecoder; + GMPTask* mTask; + }; + + GetPlatform()->runonmainthread(new MaybeRunTask(this, aTask)); +} diff --git a/media/gmp-clearkey/0.1/VideoDecoder.h b/media/gmp-clearkey/0.1/VideoDecoder.h index 4c222b24afea..7b32a86a0650 100644 --- a/media/gmp-clearkey/0.1/VideoDecoder.h +++ b/media/gmp-clearkey/0.1/VideoDecoder.h @@ -18,28 +18,37 @@ #define __VideoDecoder_h__ #include -#include -#include -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" +#include "gmp-task-utils.h" +#include "gmp-video-decode.h" +#include "gmp-video-host.h" #include "WMFH264Decoder.h" -class VideoDecoder : public RefCounted +#include "mfobjects.h" + +class VideoDecoder : public GMPVideoDecoder + , public RefCounted { public: - explicit VideoDecoder(cdm::Host_8 *aHost); + explicit VideoDecoder(GMPVideoHost *aHostAPI); - cdm::Status InitDecode(const cdm::VideoDecoderConfig& aConfig); + virtual void InitDecode(const GMPVideoCodec& aCodecSettings, + const uint8_t* aCodecSpecific, + uint32_t aCodecSpecificLength, + GMPVideoDecoderCallback* aCallback, + int32_t aCoreCount) override; - cdm::Status Decode(const cdm::InputBuffer& aEncryptedBuffer, - cdm::VideoFrame* aVideoFrame); + virtual void Decode(GMPVideoEncodedFrame* aInputFrame, + bool aMissingFrames, + const uint8_t* aCodecSpecific, + uint32_t aCodecSpecificLength, + int64_t aRenderTimeMs = -1); - void Reset(); + virtual void Reset() override; - void DecodingComplete(); + virtual void Drain() override; + + virtual void DecodingComplete() override; bool HasShutdown() { return mHasShutdown; } @@ -47,26 +56,53 @@ private: virtual ~VideoDecoder(); - cdm::Status Drain(cdm::VideoFrame* aVideoFrame); + void EnsureWorker(); + + void DrainTask(); struct DecodeData { + DecodeData() + : mTimestamp(0) + , mDuration(0) + , mIsKeyframe(false) + {} std::vector mBuffer; - uint64_t mTimestamp = 0; + uint64_t mTimestamp; + uint64_t mDuration; + bool mIsKeyframe; CryptoMetaData mCrypto; }; - cdm::Status OutputFrame(cdm::VideoFrame* aVideoFrame); + void DecodeTask(DecodeData* aData); + + void ResetCompleteTask(); + + void ReturnOutput(IMFSample* aSample, + int32_t aWidth, + int32_t aHeight, + int32_t aStride); HRESULT SampleToVideoFrame(IMFSample* aSample, int32_t aWidth, int32_t aHeight, int32_t aStride, - cdm::VideoFrame* aVideoFrame); + GMPVideoi420Frame* aVideoFrame); - cdm::Host_8* mHost; + void MaybeRunOnMainThread(GMPTask* aTask); + + GMPVideoHost *mHostAPI; // host-owned, invalid at DecodingComplete + GMPVideoDecoderCallback* mCallback; // host-owned, invalid at DecodingComplete + GMPThread* mWorkerThread; + GMPMutex* mMutex; wmf::AutoPtr mDecoder; - std::queue> mOutputQueue; + std::vector mExtraData; + std::vector mAnnexB; + + int32_t mNumInputTasks; + bool mSentExtraData; + + std::atomic mIsFlushing; bool mHasShutdown; }; diff --git a/media/gmp-clearkey/0.1/WMFH264Decoder.cpp b/media/gmp-clearkey/0.1/WMFH264Decoder.cpp index af2211f11083..6aa9628b2833 100644 --- a/media/gmp-clearkey/0.1/WMFH264Decoder.cpp +++ b/media/gmp-clearkey/0.1/WMFH264Decoder.cpp @@ -196,6 +196,7 @@ HRESULT WMFH264Decoder::CreateInputSample(const uint8_t* aData, uint32_t aDataSize, Microseconds aTimestamp, + Microseconds aDuration, IMFSample** aOutSample) { HRESULT hr; @@ -230,6 +231,8 @@ WMFH264Decoder::CreateInputSample(const uint8_t* aData, hr = sample->SetSampleTime(UsecsToHNs(aTimestamp)); ENSURE(SUCCEEDED(hr), hr); + sample->SetSampleDuration(UsecsToHNs(aDuration)); + *aOutSample = sample.Detach(); return S_OK; @@ -298,11 +301,12 @@ WMFH264Decoder::GetOutputSample(IMFSample** aOutSample) HRESULT WMFH264Decoder::Input(const uint8_t* aData, uint32_t aDataSize, - Microseconds aTimestamp) + Microseconds aTimestamp, + Microseconds aDuration) { HRESULT hr; CComPtr input = nullptr; - hr = CreateInputSample(aData, aDataSize, aTimestamp, &input); + hr = CreateInputSample(aData, aDataSize, aTimestamp, aDuration, &input); ENSURE(SUCCEEDED(hr) && input!=nullptr, hr); hr = mDecoder->ProcessInput(0, input, 0); diff --git a/media/gmp-clearkey/0.1/WMFH264Decoder.h b/media/gmp-clearkey/0.1/WMFH264Decoder.h index 554be4bd2cfa..91b7e046ffb1 100644 --- a/media/gmp-clearkey/0.1/WMFH264Decoder.h +++ b/media/gmp-clearkey/0.1/WMFH264Decoder.h @@ -30,7 +30,8 @@ public: HRESULT Input(const uint8_t* aData, uint32_t aDataSize, - Microseconds aTimestamp); + Microseconds aTimestamp, + Microseconds aDuration); HRESULT Output(IMFSample** aOutput); @@ -52,6 +53,7 @@ private: HRESULT CreateInputSample(const uint8_t* aData, uint32_t aDataSize, Microseconds aTimestamp, + Microseconds aDuration, IMFSample** aOutSample); HRESULT CreateOutputSample(IMFSample** aOutSample); diff --git a/media/gmp-clearkey/0.1/WMFUtils.h b/media/gmp-clearkey/0.1/WMFUtils.h index 75e76f7902ef..15af03ee449d 100644 --- a/media/gmp-clearkey/0.1/WMFUtils.h +++ b/media/gmp-clearkey/0.1/WMFUtils.h @@ -119,8 +119,8 @@ typedef int64_t Microseconds; #define ENSURE(condition, ret) \ { if (!(condition)) { LOG("##condition## FAILED %S:%d\n", __FILE__, __LINE__); return ret; } } -#define STATUS_SUCCEEDED(x) ((x) == Status::kSuccess) -#define STATUS_FAILED(x) ((x) != Status::kSuccess) +#define GMP_SUCCEEDED(x) ((x) == GMPNoErr) +#define GMP_FAILED(x) ((x) != GMPNoErr) #define MFPLAT_FUNC(_func, _dllname) \ extern decltype(::_func)* _func; diff --git a/media/gmp-clearkey/0.1/gmp-clearkey.cpp b/media/gmp-clearkey/0.1/gmp-clearkey.cpp index 64dbf3578fda..9b77d4bf9a90 100644 --- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp +++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp @@ -18,47 +18,68 @@ #include #include -#include "ClearKeyCDM.h" +#include "ClearKeyAsyncShutdown.h" #include "ClearKeySessionManager.h" -// This include is required in order for content_decryption_module to work -// on Unix systems. -#include "stddef.h" -#include "content_decryption_module.h" +#include "gmp-api/gmp-async-shutdown.h" +#include "gmp-api/gmp-decryption.h" +#include "gmp-api/gmp-platform.h" -#ifdef ENABLE_WMF +#if defined(ENABLE_WMF) #include "WMFUtils.h" -#endif // ENABLE_WMF +#include "VideoDecoder.h" +#endif + +#if defined(WIN32) +#define GMP_EXPORT __declspec(dllexport) +#else +#define GMP_EXPORT __attribute__((visibility("default"))) +#endif + +static GMPPlatformAPI* sPlatform = nullptr; +GMPPlatformAPI* +GetPlatform() +{ + return sPlatform; +} extern "C" { -CDM_EXPORT -void INITIALIZE_CDM_MODULE() { - +GMP_EXPORT GMPErr +GMPInit(GMPPlatformAPI* aPlatformAPI) +{ + sPlatform = aPlatformAPI; + return GMPNoErr; } -CDM_EXPORT -void* CreateCdmInstance(int cdm_interface_version, - const char* key_system, - uint32_t key_system_size, - GetCdmHostFunc get_cdm_host_func, - void* user_data) +GMP_EXPORT GMPErr +GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI) { + CK_LOGD("ClearKey GMPGetAPI |%s|", aApiName); + assert(!*aPluginAPI); - CK_LOGE("ClearKey CreateCDMInstance"); - -#ifdef ENABLE_WMF - if (!wmf::EnsureLibs()) { - CK_LOGE("Required libraries were not found"); - return nullptr; + if (!strcmp(aApiName, GMP_API_DECRYPTOR)) { + *aPluginAPI = new ClearKeySessionManager(); + } +#if defined(ENABLE_WMF) + else if (!strcmp(aApiName, GMP_API_VIDEO_DECODER) && + wmf::EnsureLibs()) { + *aPluginAPI = new VideoDecoder(static_cast(aHostAPI)); } #endif + else if (!strcmp(aApiName, GMP_API_ASYNC_SHUTDOWN)) { + *aPluginAPI = new ClearKeyAsyncShutdown(static_cast (aHostAPI)); + } else { + CK_LOGE("GMPGetAPI couldn't resolve API name |%s|\n", aApiName); + } - cdm::Host_8* host = static_cast( - get_cdm_host_func(cdm_interface_version, user_data)); - ClearKeyCDM* clearKey = new ClearKeyCDM(host); - - CK_LOGE("Created ClearKeyCDM instance!"); - - return clearKey; + return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr; } + +GMP_EXPORT GMPErr +GMPShutdown(void) +{ + CK_LOGD("ClearKey GMPShutdown"); + return GMPNoErr; +} + } diff --git a/media/gmp-clearkey/0.1/gmp-task-utils-generated.h b/media/gmp-clearkey/0.1/gmp-task-utils-generated.h new file mode 100644 index 000000000000..597ed4721030 --- /dev/null +++ b/media/gmp-clearkey/0.1/gmp-task-utils-generated.h @@ -0,0 +1,1938 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RefCounted.h" + +// 0 arguments -- +template class gmp_task_args_nm_0 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_0(M m) : + m_(m) {} + + void Run() { + m_(); + } + + private: + M m_; +}; + + + +// 0 arguments -- +template class gmp_task_args_nm_0_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_0_ret(M m, R *r) : + m_(m), r_(r) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(); + } + + private: + M m_; + R* r_; +}; + + + +// 0 arguments -- +template class gmp_task_args_m_0 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_0(C o, M m) : + o_(o), m_(m) {} + + void Run() { + ((*o_).*m_)(); + } + + private: + C o_; + M m_; +}; + + + +// 0 arguments -- +template class gmp_task_args_m_0_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_0_ret(C o, M m, R *r) : + o_(o), m_(m), r_(r) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(); + } + + private: + C o_; + M m_; + R* r_; +}; + + + +// 1 arguments -- +template class gmp_task_args_nm_1 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_1(M m, A0 a0) : + m_(m), a0_(a0) {} + + void Run() { + m_(a0_); + } + + private: + M m_; + A0 a0_; +}; + + + +// 1 arguments -- +template class gmp_task_args_nm_1_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_1_ret(M m, A0 a0, R *r) : + m_(m), r_(r), a0_(a0) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_); + } + + private: + M m_; + R* r_; + A0 a0_; +}; + + + +// 1 arguments -- +template class gmp_task_args_m_1 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_1(C o, M m, A0 a0) : + o_(o), m_(m), a0_(a0) {} + + void Run() { + ((*o_).*m_)(a0_); + } + + private: + C o_; + M m_; + A0 a0_; +}; + + + +// 1 arguments -- +template class gmp_task_args_m_1_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_1_ret(C o, M m, A0 a0, R *r) : + o_(o), m_(m), r_(r), a0_(a0) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; +}; + + + +// 2 arguments -- +template class gmp_task_args_nm_2 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_2(M m, A0 a0, A1 a1) : + m_(m), a0_(a0), a1_(a1) {} + + void Run() { + m_(a0_, a1_); + } + + private: + M m_; + A0 a0_; + A1 a1_; +}; + + + +// 2 arguments -- +template class gmp_task_args_nm_2_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_2_ret(M m, A0 a0, A1 a1, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; +}; + + + +// 2 arguments -- +template class gmp_task_args_m_2 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_2(C o, M m, A0 a0, A1 a1) : + o_(o), m_(m), a0_(a0), a1_(a1) {} + + void Run() { + ((*o_).*m_)(a0_, a1_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; +}; + + + +// 2 arguments -- +template class gmp_task_args_m_2_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_2_ret(C o, M m, A0 a0, A1 a1, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; +}; + + + +// 3 arguments -- +template class gmp_task_args_nm_3 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_3(M m, A0 a0, A1 a1, A2 a2) : + m_(m), a0_(a0), a1_(a1), a2_(a2) {} + + void Run() { + m_(a0_, a1_, a2_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 3 arguments -- +template class gmp_task_args_nm_3_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_3_ret(M m, A0 a0, A1 a1, A2 a2, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 3 arguments -- +template class gmp_task_args_m_3 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_3(C o, M m, A0 a0, A1 a1, A2 a2) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 3 arguments -- +template class gmp_task_args_m_3_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_3_ret(C o, M m, A0 a0, A1 a1, A2 a2, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; +}; + + + +// 4 arguments -- +template class gmp_task_args_nm_4 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_4(M m, A0 a0, A1 a1, A2 a2, A3 a3) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + + void Run() { + m_(a0_, a1_, a2_, a3_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 4 arguments -- +template class gmp_task_args_nm_4_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_4_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 4 arguments -- +template class gmp_task_args_m_4 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_4(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 4 arguments -- +template class gmp_task_args_m_4_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_4_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; +}; + + + +// 5 arguments -- +template class gmp_task_args_nm_5 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_5(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 5 arguments -- +template class gmp_task_args_nm_5_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_5_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 5 arguments -- +template class gmp_task_args_m_5 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_5(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 5 arguments -- +template class gmp_task_args_m_5_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_5_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; +}; + + + +// 6 arguments -- +template class gmp_task_args_nm_6 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_6(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 6 arguments -- +template class gmp_task_args_nm_6_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_6_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 6 arguments -- +template class gmp_task_args_m_6 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_6(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 6 arguments -- +template class gmp_task_args_m_6_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_6_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; +}; + + + +// 7 arguments -- +template class gmp_task_args_nm_7 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_7(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 7 arguments -- +template class gmp_task_args_nm_7_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_7_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 7 arguments -- +template class gmp_task_args_m_7 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_7(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 7 arguments -- +template class gmp_task_args_m_7_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_7_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; +}; + + + +// 8 arguments -- +template class gmp_task_args_nm_8 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_8(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 8 arguments -- +template class gmp_task_args_nm_8_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_8_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 8 arguments -- +template class gmp_task_args_m_8 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_8(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 8 arguments -- +template class gmp_task_args_m_8_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_8_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; +}; + + + +// 9 arguments -- +template class gmp_task_args_nm_9 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_9(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 9 arguments -- +template class gmp_task_args_nm_9_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_9_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 9 arguments -- +template class gmp_task_args_m_9 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_9(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 9 arguments -- +template class gmp_task_args_m_9_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_9_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; +}; + + + +// 10 arguments -- +template class gmp_task_args_nm_10 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_10(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 10 arguments -- +template class gmp_task_args_nm_10_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_10_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 10 arguments -- +template class gmp_task_args_m_10 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_10(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 10 arguments -- +template class gmp_task_args_m_10_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_10_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; +}; + + + +// 11 arguments -- +template class gmp_task_args_nm_11 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_11(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 11 arguments -- +template class gmp_task_args_nm_11_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_11_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 11 arguments -- +template class gmp_task_args_m_11 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_11(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 11 arguments -- +template class gmp_task_args_m_11_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_11_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; +}; + + + +// 12 arguments -- +template class gmp_task_args_nm_12 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_12(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 12 arguments -- +template class gmp_task_args_nm_12_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_12_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 12 arguments -- +template class gmp_task_args_m_12 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_12(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 12 arguments -- +template class gmp_task_args_m_12_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_12_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; +}; + + + +// 13 arguments -- +template class gmp_task_args_nm_13 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_13(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 13 arguments -- +template class gmp_task_args_nm_13_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_13_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 13 arguments -- +template class gmp_task_args_m_13 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_13(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 13 arguments -- +template class gmp_task_args_m_13_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_13_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; +}; + + + +// 14 arguments -- +template class gmp_task_args_nm_14 : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_14(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) : + m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + + void Run() { + m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + +// 14 arguments -- +template class gmp_task_args_nm_14_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_nm_14_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) : + m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + +// 14 arguments -- +template class gmp_task_args_m_14 : public gmp_task_args_base { + public: + explicit gmp_task_args_m_14(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) : + o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + + void Run() { + ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + C o_; + M m_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + +// 14 arguments -- +template class gmp_task_args_m_14_ret : public gmp_task_args_base { + public: + explicit gmp_task_args_m_14_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) : + o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} + virtual bool returns_value() const { return true; } + + void Run() { + *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); + } + + private: + C o_; + M m_; + R* r_; + A0 a0_; + A1 a1_; + A2 a2_; + A3 a3_; + A4 a4_; + A5 a5_; + A6 a6_; + A7 a7_; + A8 a8_; + A9 a9_; + A10 a10_; + A11 a11_; + A12 a12_; + A13 a13_; +}; + + + + + + +// 0 arguments -- +template +gmp_task_args_nm_0* WrapTaskNM(M m) { + return new gmp_task_args_nm_0 + (m); +} + +// 0 arguments -- +template +gmp_task_args_nm_0_ret* WrapTaskNMRet(M m, R* r) { + return new gmp_task_args_nm_0_ret + (m, r); +} + +// 0 arguments -- +template +gmp_task_args_m_0* WrapTask(C o, M m) { + return new gmp_task_args_m_0 + (o, m); +} + +// 0 arguments -- +template +gmp_task_args_m_0_ret* WrapTaskRet(C o, M m, R* r) { + return new gmp_task_args_m_0_ret + (o, m, r); +} + +// 1 arguments -- +template +gmp_task_args_nm_1* WrapTaskNM(M m, A0 a0) { + return new gmp_task_args_nm_1 + (m, a0); +} + +// 1 arguments -- +template +gmp_task_args_nm_1_ret* WrapTaskNMRet(M m, A0 a0, R* r) { + return new gmp_task_args_nm_1_ret + (m, a0, r); +} + +// 1 arguments -- +template +gmp_task_args_m_1* WrapTask(C o, M m, A0 a0) { + return new gmp_task_args_m_1 + (o, m, a0); +} + +// 1 arguments -- +template +gmp_task_args_m_1_ret* WrapTaskRet(C o, M m, A0 a0, R* r) { + return new gmp_task_args_m_1_ret + (o, m, a0, r); +} + +// 2 arguments -- +template +gmp_task_args_nm_2* WrapTaskNM(M m, A0 a0, A1 a1) { + return new gmp_task_args_nm_2 + (m, a0, a1); +} + +// 2 arguments -- +template +gmp_task_args_nm_2_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, R* r) { + return new gmp_task_args_nm_2_ret + (m, a0, a1, r); +} + +// 2 arguments -- +template +gmp_task_args_m_2* WrapTask(C o, M m, A0 a0, A1 a1) { + return new gmp_task_args_m_2 + (o, m, a0, a1); +} + +// 2 arguments -- +template +gmp_task_args_m_2_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, R* r) { + return new gmp_task_args_m_2_ret + (o, m, a0, a1, r); +} + +// 3 arguments -- +template +gmp_task_args_nm_3* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2) { + return new gmp_task_args_nm_3 + (m, a0, a1, a2); +} + +// 3 arguments -- +template +gmp_task_args_nm_3_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, R* r) { + return new gmp_task_args_nm_3_ret + (m, a0, a1, a2, r); +} + +// 3 arguments -- +template +gmp_task_args_m_3* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2) { + return new gmp_task_args_m_3 + (o, m, a0, a1, a2); +} + +// 3 arguments -- +template +gmp_task_args_m_3_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, R* r) { + return new gmp_task_args_m_3_ret + (o, m, a0, a1, a2, r); +} + +// 4 arguments -- +template +gmp_task_args_nm_4* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3) { + return new gmp_task_args_nm_4 + (m, a0, a1, a2, a3); +} + +// 4 arguments -- +template +gmp_task_args_nm_4_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) { + return new gmp_task_args_nm_4_ret + (m, a0, a1, a2, a3, r); +} + +// 4 arguments -- +template +gmp_task_args_m_4* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) { + return new gmp_task_args_m_4 + (o, m, a0, a1, a2, a3); +} + +// 4 arguments -- +template +gmp_task_args_m_4_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) { + return new gmp_task_args_m_4_ret + (o, m, a0, a1, a2, a3, r); +} + +// 5 arguments -- +template +gmp_task_args_nm_5* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return new gmp_task_args_nm_5 + (m, a0, a1, a2, a3, a4); +} + +// 5 arguments -- +template +gmp_task_args_nm_5_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) { + return new gmp_task_args_nm_5_ret + (m, a0, a1, a2, a3, a4, r); +} + +// 5 arguments -- +template +gmp_task_args_m_5* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return new gmp_task_args_m_5 + (o, m, a0, a1, a2, a3, a4); +} + +// 5 arguments -- +template +gmp_task_args_m_5_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) { + return new gmp_task_args_m_5_ret + (o, m, a0, a1, a2, a3, a4, r); +} + +// 6 arguments -- +template +gmp_task_args_nm_6* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return new gmp_task_args_nm_6 + (m, a0, a1, a2, a3, a4, a5); +} + +// 6 arguments -- +template +gmp_task_args_nm_6_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) { + return new gmp_task_args_nm_6_ret + (m, a0, a1, a2, a3, a4, a5, r); +} + +// 6 arguments -- +template +gmp_task_args_m_6* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return new gmp_task_args_m_6 + (o, m, a0, a1, a2, a3, a4, a5); +} + +// 6 arguments -- +template +gmp_task_args_m_6_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) { + return new gmp_task_args_m_6_ret + (o, m, a0, a1, a2, a3, a4, a5, r); +} + +// 7 arguments -- +template +gmp_task_args_nm_7* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return new gmp_task_args_nm_7 + (m, a0, a1, a2, a3, a4, a5, a6); +} + +// 7 arguments -- +template +gmp_task_args_nm_7_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) { + return new gmp_task_args_nm_7_ret + (m, a0, a1, a2, a3, a4, a5, a6, r); +} + +// 7 arguments -- +template +gmp_task_args_m_7* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return new gmp_task_args_m_7 + (o, m, a0, a1, a2, a3, a4, a5, a6); +} + +// 7 arguments -- +template +gmp_task_args_m_7_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) { + return new gmp_task_args_m_7_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, r); +} + +// 8 arguments -- +template +gmp_task_args_nm_8* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return new gmp_task_args_nm_8 + (m, a0, a1, a2, a3, a4, a5, a6, a7); +} + +// 8 arguments -- +template +gmp_task_args_nm_8_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) { + return new gmp_task_args_nm_8_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, r); +} + +// 8 arguments -- +template +gmp_task_args_m_8* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return new gmp_task_args_m_8 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7); +} + +// 8 arguments -- +template +gmp_task_args_m_8_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) { + return new gmp_task_args_m_8_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, r); +} + +// 9 arguments -- +template +gmp_task_args_nm_9* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return new gmp_task_args_nm_9 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +// 9 arguments -- +template +gmp_task_args_nm_9_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) { + return new gmp_task_args_nm_9_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r); +} + +// 9 arguments -- +template +gmp_task_args_m_9* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return new gmp_task_args_m_9 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +// 9 arguments -- +template +gmp_task_args_m_9_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) { + return new gmp_task_args_m_9_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r); +} + +// 10 arguments -- +template +gmp_task_args_nm_10* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return new gmp_task_args_nm_10 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); +} + +// 10 arguments -- +template +gmp_task_args_nm_10_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) { + return new gmp_task_args_nm_10_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r); +} + +// 10 arguments -- +template +gmp_task_args_m_10* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return new gmp_task_args_m_10 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); +} + +// 10 arguments -- +template +gmp_task_args_m_10_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) { + return new gmp_task_args_m_10_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r); +} + +// 11 arguments -- +template +gmp_task_args_nm_11* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { + return new gmp_task_args_nm_11 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); +} + +// 11 arguments -- +template +gmp_task_args_nm_11_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) { + return new gmp_task_args_nm_11_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r); +} + +// 11 arguments -- +template +gmp_task_args_m_11* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { + return new gmp_task_args_m_11 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); +} + +// 11 arguments -- +template +gmp_task_args_m_11_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) { + return new gmp_task_args_m_11_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r); +} + +// 12 arguments -- +template +gmp_task_args_nm_12* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) { + return new gmp_task_args_nm_12 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +// 12 arguments -- +template +gmp_task_args_nm_12_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) { + return new gmp_task_args_nm_12_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r); +} + +// 12 arguments -- +template +gmp_task_args_m_12* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) { + return new gmp_task_args_m_12 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +// 12 arguments -- +template +gmp_task_args_m_12_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) { + return new gmp_task_args_m_12_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r); +} + +// 13 arguments -- +template +gmp_task_args_nm_13* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) { + return new gmp_task_args_nm_13 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); +} + +// 13 arguments -- +template +gmp_task_args_nm_13_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) { + return new gmp_task_args_nm_13_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r); +} + +// 13 arguments -- +template +gmp_task_args_m_13* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) { + return new gmp_task_args_m_13 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); +} + +// 13 arguments -- +template +gmp_task_args_m_13_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) { + return new gmp_task_args_m_13_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r); +} + +// 14 arguments -- +template +gmp_task_args_nm_14* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) { + return new gmp_task_args_nm_14 + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); +} + +// 14 arguments -- +template +gmp_task_args_nm_14_ret* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) { + return new gmp_task_args_nm_14_ret + (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r); +} + +// 14 arguments -- +template +gmp_task_args_m_14* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) { + return new gmp_task_args_m_14 + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); +} + +// 14 arguments -- +template +gmp_task_args_m_14_ret* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) { + return new gmp_task_args_m_14_ret + (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r); +} + +class RefCountTaskWrapper : public gmp_task_args_base { +public: + RefCountTaskWrapper(GMPTask* aTask, RefCounted* aRefCounted) + : mTask(aTask) + , mRefCounted(aRefCounted) + {} + virtual void Run() override { + mTask->Run(); + } + virtual void Destroy() override { + mTask->Destroy(); + gmp_task_args_base::Destroy(); + } +private: + ~RefCountTaskWrapper() {} + + GMPTask* mTask; + RefPtr mRefCounted; +}; + +template +GMPTask* +WrapTaskRefCounted(Type* aType, Method aMethod, Args&&... args) +{ + GMPTask* t = WrapTask(aType, aMethod, std::forward(args)...); + return new RefCountTaskWrapper(t, aType); +} diff --git a/media/gmp-clearkey/0.1/gmp-task-utils.h b/media/gmp-clearkey/0.1/gmp-task-utils.h new file mode 100644 index 000000000000..82e08373f20e --- /dev/null +++ b/media/gmp-clearkey/0.1/gmp-task-utils.h @@ -0,0 +1,47 @@ +/* + * Copyright 2015, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Original author: ekr@rtfm.com + +#ifndef gmp_task_utils_h_ +#define gmp_task_utils_h_ + +#include "gmp-api/gmp-platform.h" + +class gmp_task_args_base : public GMPTask { +public: + virtual void Destroy() { delete this; } + virtual void Run() = 0; +}; + +// The generated file contains four major function templates +// (in variants for arbitrary numbers of arguments up to 10, +// which is why it is machine generated). The four templates +// are: +// +// WrapTask(o, m, ...) -- wraps a member function m of an object ptr o +// WrapTaskRet(o, m, ..., r) -- wraps a member function m of an object ptr o +// the function returns something that can +// be assigned to *r +// WrapTaskNM(f, ...) -- wraps a function f +// WrapTaskNMRet(f, ..., r) -- wraps a function f that returns something +// that can be assigned to *r +// +// All of these template functions return a GMPTask* which can be passed +// to DispatchXX(). +#include "gmp-task-utils-generated.h" + +#endif // gmp_task_utils_h_ diff --git a/media/gmp-clearkey/0.1/moz.build b/media/gmp-clearkey/0.1/moz.build index 1e65e2d8d9a2..1c9f5cb6946e 100644 --- a/media/gmp-clearkey/0.1/moz.build +++ b/media/gmp-clearkey/0.1/moz.build @@ -11,8 +11,8 @@ FINAL_TARGET = 'dist/bin/gmp-clearkey/0.1' FINAL_TARGET_PP_FILES += ['manifest.json.in'] UNIFIED_SOURCES += [ + 'ClearKeyAsyncShutdown.cpp', 'ClearKeyBase64.cpp', - 'ClearKeyCDM.cpp', 'ClearKeyDecryptionManager.cpp', 'ClearKeyPersistence.cpp', 'ClearKeySession.cpp', @@ -28,6 +28,7 @@ SOURCES += [ if CONFIG['OS_ARCH'] == 'WINNT': UNIFIED_SOURCES += [ + 'AnnexB.cpp', 'VideoDecoder.cpp', 'WMFH264Decoder.cpp', ] @@ -42,13 +43,15 @@ if CONFIG['OS_ARCH'] == 'WINNT': DEFINES['ENABLE_WMF'] = True - -DEFINES['CDM_IMPLEMENTATION'] = True - TEST_DIRS += [ 'gtest', ] + +LOCAL_INCLUDES += [ + '/dom/media/gmp', +] + DISABLE_STL_WRAPPING = True DEFINES['MOZ_NO_MOZALLOC'] = True