media_foundation_renderer_unittest.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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_renderer.h"
  5. #include <windows.media.protection.h>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/memory/scoped_refptr.h"
  9. #include "base/task/single_thread_task_runner.h"
  10. #include "base/test/mock_callback.h"
  11. #include "base/test/scoped_feature_list.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/win/scoped_com_initializer.h"
  14. #include "media/base/bind_to_current_loop.h"
  15. #include "media/base/demuxer_stream.h"
  16. #include "media/base/media_switches.h"
  17. #include "media/base/media_util.h"
  18. #include "media/base/mock_filters.h"
  19. #include "media/base/test_helpers.h"
  20. #include "media/base/win/test_utils.h"
  21. #include "testing/gmock/include/gmock/gmock.h"
  22. using ::testing::_;
  23. using ::testing::Invoke;
  24. using ::testing::NiceMock;
  25. using ::testing::Return;
  26. using ::testing::StrictMock;
  27. namespace media {
  28. using ABI::Windows::Media::Protection::IMediaProtectionPMPServer;
  29. using Microsoft::WRL::ComPtr;
  30. class MockMediaFoundationCdmProxy : public MediaFoundationCdmProxy {
  31. public:
  32. MockMediaFoundationCdmProxy();
  33. // MediaFoundationCdmProxy.
  34. MOCK_METHOD2(GetPMPServer, HRESULT(REFIID riid, void** object_result));
  35. MOCK_METHOD6(GetInputTrustAuthority,
  36. HRESULT(uint32_t stream_id,
  37. uint32_t stream_count,
  38. const uint8_t* content_init_data,
  39. uint32_t content_init_data_size,
  40. REFIID riid,
  41. IUnknown** object_result));
  42. MOCK_METHOD2(SetLastKeyId, HRESULT(uint32_t stream_id, REFGUID key_id));
  43. MOCK_METHOD0(RefreshTrustedInput, HRESULT());
  44. MOCK_METHOD2(ProcessContentEnabler,
  45. HRESULT(IUnknown* request, IMFAsyncResult* result));
  46. MOCK_METHOD0(OnHardwareContextReset, void());
  47. MOCK_METHOD0(OnSignificantPlayback, void());
  48. MOCK_METHOD0(OnPlaybackError, void());
  49. protected:
  50. ~MockMediaFoundationCdmProxy() override;
  51. };
  52. MockMediaFoundationCdmProxy::MockMediaFoundationCdmProxy() = default;
  53. MockMediaFoundationCdmProxy::~MockMediaFoundationCdmProxy() = default;
  54. class MockMediaProtectionPMPServer
  55. : public Microsoft::WRL::RuntimeClass<
  56. Microsoft::WRL::RuntimeClassFlags<
  57. Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
  58. IMediaProtectionPMPServer> {
  59. public:
  60. MockMediaProtectionPMPServer() = default;
  61. virtual ~MockMediaProtectionPMPServer() = default;
  62. static HRESULT MakeMockMediaProtectionPMPServer(
  63. IMediaProtectionPMPServer** pmp_server) {
  64. *pmp_server = Microsoft::WRL::Make<MockMediaProtectionPMPServer>().Detach();
  65. return S_OK;
  66. }
  67. // Return E_NOINTERFACE to avoid a crash when MFMediaEngine tries to use the
  68. // mocked IPropertySet from get_Properties().
  69. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
  70. void** object_result) override {
  71. return E_NOINTERFACE;
  72. }
  73. // ABI::Windows::Media::Protection::IMediaProtectionPMPServer.
  74. MOCK_STDCALL_METHOD1(
  75. get_Properties,
  76. HRESULT(
  77. ABI::Windows::Foundation::Collections::IPropertySet** properties));
  78. };
  79. class MediaFoundationRendererTest : public testing::Test {
  80. public:
  81. MediaFoundationRendererTest() {
  82. if (!MediaFoundationRenderer::IsSupported())
  83. return;
  84. mf_cdm_proxy_ =
  85. base::MakeRefCounted<NiceMock<MockMediaFoundationCdmProxy>>();
  86. // MF MediaEngine holds IMFMediaSource (MediaFoundationSourceWrapper) even
  87. // after the test finishes, which holds a reference to the `mf_cdm_proxy_`.
  88. testing::Mock::AllowLeak(mf_cdm_proxy_.get());
  89. MockMediaProtectionPMPServer::MakeMockMediaProtectionPMPServer(
  90. &pmp_server_);
  91. LUID empty_luid{0, 0};
  92. mf_renderer_ = std::make_unique<MediaFoundationRenderer>(
  93. task_environment_.GetMainThreadTaskRunner(),
  94. std::make_unique<NullMediaLog>(), empty_luid);
  95. // Some default actions.
  96. ON_CALL(cdm_context_, GetMediaFoundationCdmProxy())
  97. .WillByDefault(Return(mf_cdm_proxy_));
  98. ON_CALL(*mf_cdm_proxy_, GetPMPServer(_, _))
  99. .WillByDefault(
  100. Invoke(this, &MediaFoundationRendererTest::GetPMPServer));
  101. // Some expected calls with return values.
  102. EXPECT_CALL(media_resource_, GetAllStreams())
  103. .WillRepeatedly(
  104. Invoke(this, &MediaFoundationRendererTest::GetAllStreams));
  105. EXPECT_CALL(media_resource_, GetType())
  106. .WillRepeatedly(Return(MediaResource::STREAM));
  107. }
  108. ~MediaFoundationRendererTest() override { mf_renderer_.reset(); }
  109. void AddStream(DemuxerStream::Type type, bool encrypted) {
  110. streams_.push_back(CreateMockDemuxerStream(type, encrypted));
  111. }
  112. std::vector<DemuxerStream*> GetAllStreams() {
  113. std::vector<DemuxerStream*> streams;
  114. for (auto& stream : streams_) {
  115. streams.push_back(stream.get());
  116. }
  117. return streams;
  118. }
  119. HRESULT GetPMPServer(REFIID riid, LPVOID* object_result) {
  120. ComPtr<IMediaProtectionPMPServer> pmp_server;
  121. if (riid != __uuidof(**(&pmp_server)) || !object_result) {
  122. return E_INVALIDARG;
  123. }
  124. return pmp_server_.CopyTo(
  125. reinterpret_cast<IMediaProtectionPMPServer**>(object_result));
  126. }
  127. protected:
  128. // IMF* interfaces (e.g. IMediaProtectionPMPServer or
  129. // IMFContentDecryptionModule) may require an MTA to run successfully.
  130. base::win::ScopedCOMInitializer com_initializer_{
  131. base::win::ScopedCOMInitializer::kMTA};
  132. base::test::TaskEnvironment task_environment_;
  133. base::MockOnceCallback<void(bool)> set_cdm_cb_;
  134. base::MockOnceCallback<void(PipelineStatus)> renderer_init_cb_;
  135. NiceMock<MockCdmContext> cdm_context_;
  136. NiceMock<MockMediaResource> media_resource_;
  137. NiceMock<MockRendererClient> renderer_client_;
  138. scoped_refptr<NiceMock<MockMediaFoundationCdmProxy>> mf_cdm_proxy_;
  139. ComPtr<IMediaProtectionPMPServer> pmp_server_;
  140. std::unique_ptr<MediaFoundationRenderer> mf_renderer_;
  141. std::vector<std::unique_ptr<StrictMock<MockDemuxerStream>>> streams_;
  142. };
  143. TEST_F(MediaFoundationRendererTest, VerifyInitWithoutSetCdm) {
  144. if (!MediaFoundationRenderer::IsSupported())
  145. return;
  146. AddStream(DemuxerStream::AUDIO, /*encrypted=*/false);
  147. AddStream(DemuxerStream::VIDEO, /*encrypted=*/true);
  148. EXPECT_CALL(renderer_init_cb_, Run(HasStatusCode(PIPELINE_OK)));
  149. mf_renderer_->Initialize(&media_resource_, &renderer_client_,
  150. renderer_init_cb_.Get());
  151. task_environment_.RunUntilIdle();
  152. }
  153. TEST_F(MediaFoundationRendererTest, SetCdmThenInit) {
  154. if (!MediaFoundationRenderer::IsSupported())
  155. return;
  156. AddStream(DemuxerStream::AUDIO, /*encrypted=*/true);
  157. AddStream(DemuxerStream::VIDEO, /*encrypted=*/true);
  158. EXPECT_CALL(set_cdm_cb_, Run(true));
  159. EXPECT_CALL(renderer_init_cb_, Run(HasStatusCode(PIPELINE_OK)));
  160. mf_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
  161. mf_renderer_->Initialize(&media_resource_, &renderer_client_,
  162. renderer_init_cb_.Get());
  163. task_environment_.RunUntilIdle();
  164. }
  165. TEST_F(MediaFoundationRendererTest, InitThenSetCdm) {
  166. if (!MediaFoundationRenderer::IsSupported())
  167. return;
  168. AddStream(DemuxerStream::AUDIO, /*encrypted=*/true);
  169. AddStream(DemuxerStream::VIDEO, /*encrypted=*/true);
  170. EXPECT_CALL(set_cdm_cb_, Run(true));
  171. EXPECT_CALL(renderer_init_cb_, Run(HasStatusCode(PIPELINE_OK)));
  172. mf_renderer_->Initialize(&media_resource_, &renderer_client_,
  173. renderer_init_cb_.Get());
  174. mf_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
  175. task_environment_.RunUntilIdle();
  176. }
  177. TEST_F(MediaFoundationRendererTest, DirectCompositionHandle) {
  178. if (!MediaFoundationRenderer::IsSupported())
  179. return;
  180. base::MockCallback<MediaFoundationRendererExtension::GetDCompSurfaceCB>
  181. get_dcomp_surface_cb;
  182. AddStream(DemuxerStream::AUDIO, /*encrypted=*/true);
  183. AddStream(DemuxerStream::VIDEO, /*encrypted=*/true);
  184. EXPECT_CALL(set_cdm_cb_, Run(true));
  185. EXPECT_CALL(renderer_init_cb_, Run(HasStatusCode(PIPELINE_OK)));
  186. // Ignore the DirectComposition handle value returned as our |pmp_server_|
  187. // has no real implementation.
  188. EXPECT_CALL(get_dcomp_surface_cb, Run(_, _));
  189. mf_renderer_->Initialize(&media_resource_, &renderer_client_,
  190. renderer_init_cb_.Get());
  191. mf_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
  192. mf_renderer_->GetDCompSurface(get_dcomp_surface_cb.Get());
  193. task_environment_.RunUntilIdle();
  194. }
  195. TEST_F(MediaFoundationRendererTest, ClearStartsInFrameServer) {
  196. if (!MediaFoundationRenderer::IsSupported())
  197. return;
  198. base::test::ScopedFeatureList feature_list;
  199. feature_list.InitAndEnableFeatureWithParameters(
  200. media::kMediaFoundationClearRendering, {{"strategy", "dynamic"}});
  201. ;
  202. AddStream(DemuxerStream::AUDIO, /*encrypted=*/false);
  203. AddStream(DemuxerStream::VIDEO, /*encrypted=*/false);
  204. mf_renderer_->Initialize(&media_resource_, &renderer_client_,
  205. renderer_init_cb_.Get());
  206. EXPECT_TRUE(mf_renderer_->InFrameServerMode());
  207. }
  208. TEST_F(MediaFoundationRendererTest, EncryptedStaysInDirectComposition) {
  209. if (!MediaFoundationRenderer::IsSupported())
  210. return;
  211. AddStream(DemuxerStream::AUDIO, /*encrypted=*/true);
  212. AddStream(DemuxerStream::VIDEO, /*encrypted=*/true);
  213. mf_renderer_->Initialize(&media_resource_, &renderer_client_,
  214. renderer_init_cb_.Get());
  215. EXPECT_FALSE(mf_renderer_->InFrameServerMode());
  216. }
  217. } // namespace media