media_foundation_protection_manager.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/renderers/win/media_foundation_protection_manager.h"
  5. #include <mferror.h>
  6. #include <windows.foundation.h>
  7. #include "base/logging.h"
  8. #include "base/strings/string_piece.h"
  9. #include "base/threading/thread_task_runner_handle.h"
  10. #include "base/time/time.h"
  11. #include "base/win/core_winrt_util.h"
  12. #include "base/win/scoped_hstring.h"
  13. #include "base/win/windows_types.h"
  14. #include "media/base/win/mf_helpers.h"
  15. namespace media {
  16. using Microsoft::WRL::ComPtr;
  17. MediaFoundationProtectionManager::MediaFoundationProtectionManager() {
  18. DVLOG_FUNC(1);
  19. }
  20. MediaFoundationProtectionManager::~MediaFoundationProtectionManager() {
  21. DVLOG_FUNC(1);
  22. }
  23. HRESULT MediaFoundationProtectionManager::RuntimeClassInitialize(
  24. scoped_refptr<base::SequencedTaskRunner> task_runner,
  25. WaitingCB waiting_cb) {
  26. DVLOG_FUNC(1);
  27. task_runner_ = std::move(task_runner);
  28. waiting_cb_ = std::move(waiting_cb);
  29. if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload())
  30. return E_FAIL;
  31. // Init an empty |property_set_| as MFMediaEngine could access it via
  32. // |get_Properties| before we populate it within SetPMPServer.
  33. base::win::ScopedHString property_set_id = base::win::ScopedHString::Create(
  34. RuntimeClass_Windows_Foundation_Collections_PropertySet);
  35. RETURN_IF_FAILED(
  36. base::win::RoActivateInstance(property_set_id.get(), &property_set_));
  37. return S_OK;
  38. }
  39. HRESULT MediaFoundationProtectionManager::SetCdmProxy(
  40. scoped_refptr<MediaFoundationCdmProxy> cdm_proxy) {
  41. DVLOG_FUNC(1);
  42. DCHECK(cdm_proxy);
  43. cdm_proxy_ = std::move(cdm_proxy);
  44. ComPtr<ABI::Windows::Media::Protection::IMediaProtectionPMPServer> pmp_server;
  45. RETURN_IF_FAILED(cdm_proxy_->GetPMPServer(IID_PPV_ARGS(&pmp_server)));
  46. RETURN_IF_FAILED(SetPMPServer(pmp_server.Get()));
  47. return S_OK;
  48. }
  49. HRESULT MediaFoundationProtectionManager::SetPMPServer(
  50. ABI::Windows::Media::Protection::IMediaProtectionPMPServer* pmp_server) {
  51. DVLOG_FUNC(1);
  52. DCHECK(pmp_server);
  53. ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>
  54. property_map;
  55. RETURN_IF_FAILED(property_set_.As(&property_map));
  56. // MFMediaEngine uses |pmp_server_key| to get the Protected Media Path (PMP)
  57. // server used for playing protected content. This is not currently documented
  58. // in MSDN.
  59. boolean replaced = false;
  60. base::win::ScopedHString pmp_server_key = base::win::ScopedHString::Create(
  61. L"Windows.Media.Protection.MediaProtectionPMPServer");
  62. RETURN_IF_FAILED(
  63. property_map->Insert(pmp_server_key.get(), pmp_server, &replaced));
  64. return S_OK;
  65. }
  66. HRESULT MediaFoundationProtectionManager::BeginEnableContent(
  67. IMFActivate* enabler_activate,
  68. IMFTopology* topology,
  69. IMFAsyncCallback* callback,
  70. IUnknown* state) {
  71. DVLOG_FUNC(1);
  72. ComPtr<IUnknown> unknown_object;
  73. ComPtr<IMFAsyncResult> async_result;
  74. RETURN_IF_FAILED(
  75. MFCreateAsyncResult(nullptr, callback, state, &async_result));
  76. RETURN_IF_FAILED(
  77. enabler_activate->ActivateObject(IID_PPV_ARGS(&unknown_object)));
  78. // |enabler_type| can be obtained from IMFContentEnabler
  79. // (https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nn-mfidl-imfcontentenabler).
  80. // If not, try IMediaProtectionServiceRequest
  81. // (https://docs.microsoft.com/en-us/uwp/api/windows.media.protection.imediaprotectionservicerequest).
  82. GUID enabler_type = GUID_NULL;
  83. ComPtr<IMFContentEnabler> content_enabler;
  84. if (SUCCEEDED(unknown_object.As(&content_enabler))) {
  85. RETURN_IF_FAILED(content_enabler->GetEnableType(&enabler_type));
  86. } else {
  87. ComPtr<ABI::Windows::Media::Protection::IMediaProtectionServiceRequest>
  88. service_request;
  89. RETURN_IF_FAILED(unknown_object.As(&service_request));
  90. RETURN_IF_FAILED(service_request->get_Type(&enabler_type));
  91. }
  92. if (enabler_type == MFENABLETYPE_MF_RebootRequired) {
  93. DLOG(ERROR) << __func__ << ": MF_E_REBOOT_REQUIRED";
  94. return MF_E_REBOOT_REQUIRED;
  95. } else if (enabler_type == MFENABLETYPE_MF_UpdateRevocationInformation) {
  96. DLOG(ERROR) << __func__ << ": MF_E_GRL_VERSION_TOO_LOW";
  97. return MF_E_GRL_VERSION_TOO_LOW;
  98. } else if (enabler_type == MFENABLETYPE_MF_UpdateUntrustedComponent) {
  99. auto hr = HRESULT_FROM_WIN32(ERROR_INVALID_IMAGE_HASH);
  100. DLOG(ERROR) << __func__ << ": hr=" << hr;
  101. return hr;
  102. } else {
  103. RETURN_IF_FAILED(cdm_proxy_->ProcessContentEnabler(unknown_object.Get(),
  104. async_result.Get()));
  105. // Force post task so `OnBeginEnableContent()` and `OnEndEnableContent()`
  106. // are always in sequence.
  107. task_runner_->PostTask(
  108. FROM_HERE,
  109. base::BindOnce(&MediaFoundationProtectionManager::OnBeginEnableContent,
  110. weak_factory_.GetWeakPtr()));
  111. }
  112. return S_OK;
  113. }
  114. HRESULT MediaFoundationProtectionManager::EndEnableContent(
  115. IMFAsyncResult* async_result) {
  116. DVLOG_FUNC(1);
  117. // Force post task so `OnBeginEnableContent()` and `OnEndEnableContent()` are
  118. // always in sequence.
  119. task_runner_->PostTask(
  120. FROM_HERE,
  121. base::BindOnce(&MediaFoundationProtectionManager::OnEndEnableContent,
  122. weak_factory_.GetWeakPtr()));
  123. // Get status from the given |async_result| for the purpose of logging.
  124. // Returns S_OK as there is no additional work being done here.
  125. HRESULT async_status = async_result->GetStatus();
  126. if (FAILED(async_status)) {
  127. DLOG(ERROR) << "Content enabling failed. hr=" << async_status;
  128. } else {
  129. DVLOG(2) << "Content enabling succeeded";
  130. }
  131. return S_OK;
  132. }
  133. // IMediaProtectionManager implementation
  134. HRESULT MediaFoundationProtectionManager::add_ServiceRequested(
  135. ABI::Windows::Media::Protection::IServiceRequestedEventHandler* handler,
  136. EventRegistrationToken* cookie) {
  137. return E_NOTIMPL;
  138. }
  139. HRESULT MediaFoundationProtectionManager::remove_ServiceRequested(
  140. EventRegistrationToken cookie) {
  141. return E_NOTIMPL;
  142. }
  143. HRESULT MediaFoundationProtectionManager::add_RebootNeeded(
  144. ABI::Windows::Media::Protection::IRebootNeededEventHandler* handler,
  145. EventRegistrationToken* cookie) {
  146. return E_NOTIMPL;
  147. }
  148. HRESULT MediaFoundationProtectionManager::remove_RebootNeeded(
  149. EventRegistrationToken cookie) {
  150. return E_NOTIMPL;
  151. }
  152. HRESULT MediaFoundationProtectionManager::add_ComponentLoadFailed(
  153. ABI::Windows::Media::Protection::IComponentLoadFailedEventHandler* handler,
  154. EventRegistrationToken* cookie) {
  155. return E_NOTIMPL;
  156. }
  157. HRESULT MediaFoundationProtectionManager::remove_ComponentLoadFailed(
  158. EventRegistrationToken cookie) {
  159. return E_NOTIMPL;
  160. }
  161. HRESULT MediaFoundationProtectionManager::get_Properties(
  162. ABI::Windows::Foundation::Collections::IPropertySet** properties) {
  163. DVLOG_FUNC(2);
  164. if (!properties)
  165. return E_POINTER;
  166. return property_set_.CopyTo(properties);
  167. }
  168. void MediaFoundationProtectionManager::OnBeginEnableContent() {
  169. DVLOG_FUNC(2);
  170. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  171. // If EnableContent takes too long, report waiting for key status. Choose a
  172. // timeout of 500ms to be on the safe side, e.g. on slower machines.
  173. const auto kWaitingForKeyTimeOut = base::Milliseconds(500);
  174. waiting_for_key_time_out_cb_.Reset(
  175. base::BindOnce(&MediaFoundationProtectionManager::OnWaitingForKeyTimeOut,
  176. weak_factory_.GetWeakPtr()));
  177. task_runner_->PostDelayedTask(FROM_HERE,
  178. waiting_for_key_time_out_cb_.callback(),
  179. kWaitingForKeyTimeOut);
  180. }
  181. void MediaFoundationProtectionManager::OnEndEnableContent() {
  182. DVLOG_FUNC(2);
  183. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  184. waiting_for_key_time_out_cb_.Cancel();
  185. }
  186. void MediaFoundationProtectionManager::OnWaitingForKeyTimeOut() {
  187. DVLOG_FUNC(2);
  188. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  189. waiting_for_key_time_out_cb_.Cancel();
  190. waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
  191. }
  192. } // namespace media