123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "media/renderers/win/media_foundation_protection_manager.h"
- #include <mferror.h>
- #include <windows.foundation.h>
- #include "base/logging.h"
- #include "base/strings/string_piece.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/win/core_winrt_util.h"
- #include "base/win/scoped_hstring.h"
- #include "base/win/windows_types.h"
- #include "media/base/win/mf_helpers.h"
- namespace media {
- using Microsoft::WRL::ComPtr;
- MediaFoundationProtectionManager::MediaFoundationProtectionManager() {
- DVLOG_FUNC(1);
- }
- MediaFoundationProtectionManager::~MediaFoundationProtectionManager() {
- DVLOG_FUNC(1);
- }
- HRESULT MediaFoundationProtectionManager::RuntimeClassInitialize(
- scoped_refptr<base::SequencedTaskRunner> task_runner,
- WaitingCB waiting_cb) {
- DVLOG_FUNC(1);
- task_runner_ = std::move(task_runner);
- waiting_cb_ = std::move(waiting_cb);
- if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload())
- return E_FAIL;
- // Init an empty |property_set_| as MFMediaEngine could access it via
- // |get_Properties| before we populate it within SetPMPServer.
- base::win::ScopedHString property_set_id = base::win::ScopedHString::Create(
- RuntimeClass_Windows_Foundation_Collections_PropertySet);
- RETURN_IF_FAILED(
- base::win::RoActivateInstance(property_set_id.get(), &property_set_));
- return S_OK;
- }
- HRESULT MediaFoundationProtectionManager::SetCdmProxy(
- scoped_refptr<MediaFoundationCdmProxy> cdm_proxy) {
- DVLOG_FUNC(1);
- DCHECK(cdm_proxy);
- cdm_proxy_ = std::move(cdm_proxy);
- ComPtr<ABI::Windows::Media::Protection::IMediaProtectionPMPServer> pmp_server;
- RETURN_IF_FAILED(cdm_proxy_->GetPMPServer(IID_PPV_ARGS(&pmp_server)));
- RETURN_IF_FAILED(SetPMPServer(pmp_server.Get()));
- return S_OK;
- }
- HRESULT MediaFoundationProtectionManager::SetPMPServer(
- ABI::Windows::Media::Protection::IMediaProtectionPMPServer* pmp_server) {
- DVLOG_FUNC(1);
- DCHECK(pmp_server);
- ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>
- property_map;
- RETURN_IF_FAILED(property_set_.As(&property_map));
- // MFMediaEngine uses |pmp_server_key| to get the Protected Media Path (PMP)
- // server used for playing protected content. This is not currently documented
- // in MSDN.
- boolean replaced = false;
- base::win::ScopedHString pmp_server_key = base::win::ScopedHString::Create(
- L"Windows.Media.Protection.MediaProtectionPMPServer");
- RETURN_IF_FAILED(
- property_map->Insert(pmp_server_key.get(), pmp_server, &replaced));
- return S_OK;
- }
- HRESULT MediaFoundationProtectionManager::BeginEnableContent(
- IMFActivate* enabler_activate,
- IMFTopology* topology,
- IMFAsyncCallback* callback,
- IUnknown* state) {
- DVLOG_FUNC(1);
- ComPtr<IUnknown> unknown_object;
- ComPtr<IMFAsyncResult> async_result;
- RETURN_IF_FAILED(
- MFCreateAsyncResult(nullptr, callback, state, &async_result));
- RETURN_IF_FAILED(
- enabler_activate->ActivateObject(IID_PPV_ARGS(&unknown_object)));
- // |enabler_type| can be obtained from IMFContentEnabler
- // (https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nn-mfidl-imfcontentenabler).
- // If not, try IMediaProtectionServiceRequest
- // (https://docs.microsoft.com/en-us/uwp/api/windows.media.protection.imediaprotectionservicerequest).
- GUID enabler_type = GUID_NULL;
- ComPtr<IMFContentEnabler> content_enabler;
- if (SUCCEEDED(unknown_object.As(&content_enabler))) {
- RETURN_IF_FAILED(content_enabler->GetEnableType(&enabler_type));
- } else {
- ComPtr<ABI::Windows::Media::Protection::IMediaProtectionServiceRequest>
- service_request;
- RETURN_IF_FAILED(unknown_object.As(&service_request));
- RETURN_IF_FAILED(service_request->get_Type(&enabler_type));
- }
- if (enabler_type == MFENABLETYPE_MF_RebootRequired) {
- DLOG(ERROR) << __func__ << ": MF_E_REBOOT_REQUIRED";
- return MF_E_REBOOT_REQUIRED;
- } else if (enabler_type == MFENABLETYPE_MF_UpdateRevocationInformation) {
- DLOG(ERROR) << __func__ << ": MF_E_GRL_VERSION_TOO_LOW";
- return MF_E_GRL_VERSION_TOO_LOW;
- } else if (enabler_type == MFENABLETYPE_MF_UpdateUntrustedComponent) {
- auto hr = HRESULT_FROM_WIN32(ERROR_INVALID_IMAGE_HASH);
- DLOG(ERROR) << __func__ << ": hr=" << hr;
- return hr;
- } else {
- RETURN_IF_FAILED(cdm_proxy_->ProcessContentEnabler(unknown_object.Get(),
- async_result.Get()));
- // Force post task so `OnBeginEnableContent()` and `OnEndEnableContent()`
- // are always in sequence.
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MediaFoundationProtectionManager::OnBeginEnableContent,
- weak_factory_.GetWeakPtr()));
- }
- return S_OK;
- }
- HRESULT MediaFoundationProtectionManager::EndEnableContent(
- IMFAsyncResult* async_result) {
- DVLOG_FUNC(1);
- // Force post task so `OnBeginEnableContent()` and `OnEndEnableContent()` are
- // always in sequence.
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MediaFoundationProtectionManager::OnEndEnableContent,
- weak_factory_.GetWeakPtr()));
- // Get status from the given |async_result| for the purpose of logging.
- // Returns S_OK as there is no additional work being done here.
- HRESULT async_status = async_result->GetStatus();
- if (FAILED(async_status)) {
- DLOG(ERROR) << "Content enabling failed. hr=" << async_status;
- } else {
- DVLOG(2) << "Content enabling succeeded";
- }
- return S_OK;
- }
- // IMediaProtectionManager implementation
- HRESULT MediaFoundationProtectionManager::add_ServiceRequested(
- ABI::Windows::Media::Protection::IServiceRequestedEventHandler* handler,
- EventRegistrationToken* cookie) {
- return E_NOTIMPL;
- }
- HRESULT MediaFoundationProtectionManager::remove_ServiceRequested(
- EventRegistrationToken cookie) {
- return E_NOTIMPL;
- }
- HRESULT MediaFoundationProtectionManager::add_RebootNeeded(
- ABI::Windows::Media::Protection::IRebootNeededEventHandler* handler,
- EventRegistrationToken* cookie) {
- return E_NOTIMPL;
- }
- HRESULT MediaFoundationProtectionManager::remove_RebootNeeded(
- EventRegistrationToken cookie) {
- return E_NOTIMPL;
- }
- HRESULT MediaFoundationProtectionManager::add_ComponentLoadFailed(
- ABI::Windows::Media::Protection::IComponentLoadFailedEventHandler* handler,
- EventRegistrationToken* cookie) {
- return E_NOTIMPL;
- }
- HRESULT MediaFoundationProtectionManager::remove_ComponentLoadFailed(
- EventRegistrationToken cookie) {
- return E_NOTIMPL;
- }
- HRESULT MediaFoundationProtectionManager::get_Properties(
- ABI::Windows::Foundation::Collections::IPropertySet** properties) {
- DVLOG_FUNC(2);
- if (!properties)
- return E_POINTER;
- return property_set_.CopyTo(properties);
- }
- void MediaFoundationProtectionManager::OnBeginEnableContent() {
- DVLOG_FUNC(2);
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- // If EnableContent takes too long, report waiting for key status. Choose a
- // timeout of 500ms to be on the safe side, e.g. on slower machines.
- const auto kWaitingForKeyTimeOut = base::Milliseconds(500);
- waiting_for_key_time_out_cb_.Reset(
- base::BindOnce(&MediaFoundationProtectionManager::OnWaitingForKeyTimeOut,
- weak_factory_.GetWeakPtr()));
- task_runner_->PostDelayedTask(FROM_HERE,
- waiting_for_key_time_out_cb_.callback(),
- kWaitingForKeyTimeOut);
- }
- void MediaFoundationProtectionManager::OnEndEnableContent() {
- DVLOG_FUNC(2);
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- waiting_for_key_time_out_cb_.Cancel();
- }
- void MediaFoundationProtectionManager::OnWaitingForKeyTimeOut() {
- DVLOG_FUNC(2);
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- waiting_for_key_time_out_cb_.Cancel();
- waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
- }
- } // namespace media
|