Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "WidevineAdapter.h"
7 : #include "content_decryption_module.h"
8 : #include "VideoUtils.h"
9 : #include "WidevineDecryptor.h"
10 : #include "WidevineDummyDecoder.h"
11 : #include "WidevineUtils.h"
12 : #include "WidevineVideoDecoder.h"
13 : #include "gmp-api/gmp-entrypoints.h"
14 : #include "gmp-api/gmp-decryption.h"
15 : #include "gmp-api/gmp-video-codec.h"
16 : #include "gmp-api/gmp-platform.h"
17 :
18 : const GMPPlatformAPI* sPlatform = nullptr;
19 :
20 : namespace mozilla {
21 :
22 0 : GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) {
23 0 : return sPlatform->getcurrenttime(aOutTime);
24 : }
25 :
26 : // Call on main thread only.
27 0 : GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) {
28 0 : return sPlatform->settimer(aTask, aTimeoutMS);
29 : }
30 :
31 0 : GMPErr GMPCreateRecord(const char* aRecordName,
32 : uint32_t aRecordNameSize,
33 : GMPRecord** aOutRecord,
34 : GMPRecordClient* aClient)
35 : {
36 0 : return sPlatform->createrecord(aRecordName, aRecordNameSize, aOutRecord, aClient);
37 : }
38 :
39 : void
40 0 : WidevineAdapter::SetAdaptee(PRLibrary* aLib)
41 : {
42 0 : mLib = aLib;
43 0 : }
44 :
45 0 : void* GetCdmHost(int aHostInterfaceVersion, void* aUserData)
46 : {
47 0 : CDM_LOG("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
48 0 : WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData);
49 0 : MOZ_ASSERT(decryptor);
50 0 : return static_cast<cdm::Host_8*>(decryptor);
51 : }
52 :
53 : #define STRINGIFY(s) _STRINGIFY(s)
54 : #define _STRINGIFY(s) #s
55 :
56 : GMPErr
57 0 : WidevineAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
58 : {
59 0 : sPlatform = aPlatformAPI;
60 0 : if (!mLib) {
61 0 : return GMPGenericErr;
62 : }
63 :
64 0 : auto init = reinterpret_cast<decltype(::INITIALIZE_CDM_MODULE)*>(
65 0 : PR_FindFunctionSymbol(mLib, STRINGIFY(INITIALIZE_CDM_MODULE)));
66 0 : if (!init) {
67 0 : return GMPGenericErr;
68 : }
69 :
70 0 : CDM_LOG(STRINGIFY(INITIALIZE_CDM_MODULE)"()");
71 0 : init();
72 :
73 0 : return GMPNoErr;
74 : }
75 :
76 : GMPErr
77 0 : WidevineAdapter::GMPGetAPI(const char* aAPIName,
78 : void* aHostAPI,
79 : void** aPluginAPI,
80 : uint32_t aDecryptorId)
81 : {
82 0 : CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p",
83 : aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
84 0 : if (!strcmp(aAPIName, GMP_API_DECRYPTOR)) {
85 0 : if (WidevineDecryptor::GetInstance(aDecryptorId)) {
86 : // We only support one CDM instance per PGMPDecryptor. Fail!
87 0 : CDM_LOG("WidevineAdapter::GMPGetAPI() Tried to create more than once CDM per IPDL actor! FAIL!");
88 0 : return GMPQuotaExceededErr;
89 : }
90 : auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
91 0 : PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
92 0 : if (!create) {
93 0 : CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to find CreateCdmInstance",
94 : aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
95 0 : return GMPGenericErr;
96 : }
97 :
98 0 : auto* decryptor = new WidevineDecryptor();
99 :
100 : auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
101 0 : create(cdm::ContentDecryptionModule::kVersion,
102 : kEMEKeySystemWidevine.get(),
103 : kEMEKeySystemWidevine.Length(),
104 : &GetCdmHost,
105 0 : decryptor));
106 0 : if (!cdm) {
107 0 : CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to create cdm",
108 : aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
109 0 : return GMPGenericErr;
110 : }
111 0 : CDM_LOG("cdm: 0x%p", cdm);
112 0 : RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm, decryptor));
113 0 : decryptor->SetCDM(wrapper, aDecryptorId);
114 0 : *aPluginAPI = decryptor;
115 :
116 0 : } else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) {
117 0 : RefPtr<CDMWrapper> wrapper = WidevineDecryptor::GetInstance(aDecryptorId);
118 :
119 : // There is a possible race condition, where the decryptor will be destroyed
120 : // before we are able to create the video decoder, so we create a dummy
121 : // decoder to avoid crashing.
122 0 : if (!wrapper) {
123 0 : CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p No cdm for video decoder. Using a DummyDecoder",
124 : aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
125 :
126 0 : *aPluginAPI = new WidevineDummyDecoder();
127 : } else {
128 0 : *aPluginAPI = new WidevineVideoDecoder(static_cast<GMPVideoHost*>(aHostAPI),
129 0 : wrapper);
130 : }
131 : }
132 0 : return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
133 : }
134 :
135 : void
136 0 : WidevineAdapter::GMPShutdown()
137 : {
138 0 : CDM_LOG("WidevineAdapter::GMPShutdown()");
139 :
140 : decltype(::DeinitializeCdmModule)* deinit;
141 0 : deinit = (decltype(deinit))(PR_FindFunctionSymbol(mLib, "DeinitializeCdmModule"));
142 0 : if (deinit) {
143 0 : CDM_LOG("DeinitializeCdmModule()");
144 0 : deinit();
145 : }
146 0 : }
147 :
148 : /* static */
149 : bool
150 0 : WidevineAdapter::Supports(int32_t aModuleVersion,
151 : int32_t aInterfaceVersion,
152 : int32_t aHostVersion)
153 : {
154 0 : return aModuleVersion == CDM_MODULE_VERSION &&
155 0 : aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
156 0 : aHostVersion == cdm::Host_8::kVersion;
157 : }
158 :
159 : } // namespace mozilla
|