1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/media_foundation_renderer_wrapper.h"
7 #include "base/functional/callback_helpers.h"
8 #include "base/task/sequenced_task_runner.h"
9 #include "media/base/win/mf_helpers.h"
10 #include "media/mojo/mojom/renderer_extensions.mojom.h"
11 #include "media/mojo/services/media_foundation_gpu_info_monitor.h"
12 #include "media/mojo/services/mojo_media_log.h"
13 #include "mojo/public/cpp/bindings/callback_helpers.h"
14 #include "mojo/public/cpp/system/platform_handle.h"
20 bool HasAudio(MediaResource* media_resource) {
21 DCHECK(media_resource->GetType() == MediaResource::Type::kStream);
23 const auto media_streams = media_resource->GetAllStreams();
24 for (const media::DemuxerStream* stream : media_streams) {
25 if (stream->type() == media::DemuxerStream::Type::AUDIO)
32 LUID ChromeLuidToLuid(const CHROME_LUID& chrome_luid) {
34 luid.LowPart = chrome_luid.LowPart;
35 luid.HighPart = chrome_luid.HighPart;
41 MediaFoundationRendererWrapper::MediaFoundationRendererWrapper(
42 scoped_refptr<base::SequencedTaskRunner> task_runner,
43 mojom::FrameInterfaceFactory* frame_interfaces,
44 mojo::PendingRemote<mojom::MediaLog> media_log_remote,
45 mojo::PendingReceiver<RendererExtension> renderer_extension_receiver,
46 mojo::PendingRemote<ClientExtension> client_extension_remote)
47 : frame_interfaces_(frame_interfaces),
48 renderer_extension_receiver_(this,
49 std::move(renderer_extension_receiver)),
50 client_extension_remote_(std::move(client_extension_remote), task_runner),
51 site_mute_observer_(this) {
53 DCHECK(frame_interfaces_);
55 renderer_ = std::make_unique<MediaFoundationRenderer>(
56 std::move(task_runner),
57 std::make_unique<MojoMediaLog>(std::move(media_log_remote), task_runner),
59 MediaFoundationGpuInfoMonitor::GetInstance()->gpu_luid()));
61 luid_update_subscription_ =
62 MediaFoundationGpuInfoMonitor::GetInstance()->AddLuidObserver(
63 base::BindRepeating(&MediaFoundationRendererWrapper::OnGpuLuidChange,
64 weak_factory_.GetWeakPtr()));
67 MediaFoundationRendererWrapper::~MediaFoundationRendererWrapper() {
69 if (!dcomp_surface_token_.is_empty())
70 dcomp_surface_registry_->UnregisterDCOMPSurfaceHandle(dcomp_surface_token_);
73 void MediaFoundationRendererWrapper::Initialize(
74 MediaResource* media_resource,
75 RendererClient* client,
76 PipelineStatusCallback init_cb) {
77 if (HasAudio(media_resource)) {
78 frame_interfaces_->RegisterMuteStateObserver(
79 site_mute_observer_.BindNewPipeAndPassRemote());
82 renderer_->SetFrameReturnCallbacks(
84 &MediaFoundationRendererWrapper::OnFrameGeneratedByMediaFoundation,
85 weak_factory_.GetWeakPtr()),
87 &MediaFoundationRendererWrapper::OnFramePoolInitialized,
88 weak_factory_.GetWeakPtr()));
90 renderer_->Initialize(media_resource, client, std::move(init_cb));
93 void MediaFoundationRendererWrapper::SetCdm(CdmContext* cdm_context,
94 CdmAttachedCB cdm_attached_cb) {
95 renderer_->SetCdm(cdm_context, std::move(cdm_attached_cb));
98 void MediaFoundationRendererWrapper::SetLatencyHint(
99 absl::optional<base::TimeDelta> latency_hint) {
100 renderer_->SetLatencyHint(latency_hint);
103 void MediaFoundationRendererWrapper::Flush(base::OnceClosure flush_cb) {
104 renderer_->Flush(std::move(flush_cb));
107 void MediaFoundationRendererWrapper::StartPlayingFrom(base::TimeDelta time) {
108 renderer_->StartPlayingFrom(time);
111 void MediaFoundationRendererWrapper::SetPlaybackRate(double playback_rate) {
112 renderer_->SetPlaybackRate(playback_rate);
115 void MediaFoundationRendererWrapper::SetVolume(float volume) {
117 renderer_->SetVolume(muted_ ? 0 : volume_);
120 base::TimeDelta MediaFoundationRendererWrapper::GetMediaTime() {
121 return renderer_->GetMediaTime();
124 RendererType MediaFoundationRendererWrapper::GetRendererType() {
125 return RendererType::kMediaFoundation;
128 void MediaFoundationRendererWrapper::GetDCOMPSurface(
129 GetDCOMPSurfaceCallback callback) {
130 if (has_get_dcomp_surface_called_) {
131 renderer_extension_receiver_.ReportBadMessage(
132 "GetDCOMPSurface should only be called once!");
136 has_get_dcomp_surface_called_ = true;
137 renderer_->GetDCompSurface(
138 base::BindOnce(&MediaFoundationRendererWrapper::OnReceiveDCOMPSurface,
139 weak_factory_.GetWeakPtr(), std::move(callback)));
142 void MediaFoundationRendererWrapper::SetVideoStreamEnabled(bool enabled) {
143 renderer_->SetVideoStreamEnabled(enabled);
146 void MediaFoundationRendererWrapper::SetOutputRect(
147 const gfx::Rect& output_rect,
148 SetOutputRectCallback callback) {
149 renderer_->SetOutputRect(output_rect, std::move(callback));
152 void MediaFoundationRendererWrapper::OnMuteStateChange(bool muted) {
153 DVLOG_FUNC(2) << ": muted=" << muted;
159 renderer_->SetVolume(muted_ ? 0 : volume_);
162 void MediaFoundationRendererWrapper::OnGpuLuidChange(
163 const CHROME_LUID& adapter_luid) {
164 renderer_->SetGpuProcessAdapterLuid(ChromeLuidToLuid(adapter_luid));
167 void MediaFoundationRendererWrapper::OnReceiveDCOMPSurface(
168 GetDCOMPSurfaceCallback callback,
169 base::win::ScopedHandle handle,
170 const std::string& error) {
171 if (!handle.IsValid()) {
172 std::move(callback).Run(absl::nullopt, "invalid handle: " + error);
176 if (!dcomp_surface_registry_) {
177 frame_interfaces_->CreateDCOMPSurfaceRegistry(
178 dcomp_surface_registry_.BindNewPipeAndPassReceiver());
181 auto register_cb = base::BindOnce(
182 &MediaFoundationRendererWrapper::OnDCOMPSurfaceHandleRegistered,
183 weak_factory_.GetWeakPtr(), std::move(callback));
185 dcomp_surface_registry_->RegisterDCOMPSurfaceHandle(
186 mojo::PlatformHandle(std::move(handle)),
187 mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(register_cb),
191 void MediaFoundationRendererWrapper::OnDCOMPSurfaceHandleRegistered(
192 GetDCOMPSurfaceCallback callback,
193 const absl::optional<base::UnguessableToken>& token) {
196 DCHECK(dcomp_surface_token_.is_empty());
197 dcomp_surface_token_ = token.value();
199 error = "dcomp surface handle registration failed";
202 std::move(callback).Run(token, error);
205 void MediaFoundationRendererWrapper::OnFramePoolInitialized(
206 std::vector<MediaFoundationFrameInfo> frame_textures,
207 const gfx::Size& texture_size) {
208 auto pool_params = media::mojom::FramePoolInitializationParameters::New();
209 for (auto& texture : frame_textures) {
210 auto frame_info = media::mojom::FrameTextureInfo::New();
211 gfx::GpuMemoryBufferHandle gpu_handle;
213 gpu_handle.dxgi_handle = std::move(texture.dxgi_handle);
214 gpu_handle.dxgi_token = gfx::DXGIHandleToken();
215 gpu_handle.type = gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE;
217 frame_info->token = texture.token;
218 frame_info->texture_handle = std::move(gpu_handle);
219 pool_params->frame_textures.emplace_back(std::move(frame_info));
222 pool_params->texture_size = texture_size;
223 client_extension_remote_->InitializeFramePool(std::move(pool_params));
226 void MediaFoundationRendererWrapper::OnFrameGeneratedByMediaFoundation(
227 const base::UnguessableToken& frame_token,
228 const gfx::Size& frame_size,
229 base::TimeDelta frame_timestamp) {
230 client_extension_remote_->OnFrameAvailable(frame_token, frame_size,
234 void MediaFoundationRendererWrapper::NotifyFrameReleased(
235 const base::UnguessableToken& frame_token) {
236 renderer_->NotifyFrameReleased(frame_token);
239 void MediaFoundationRendererWrapper::RequestNextFrame() {
240 renderer_->RequestNextFrame();
243 void MediaFoundationRendererWrapper::SetMediaFoundationRenderingMode(
244 MediaFoundationRenderingMode mode) {
245 renderer_->SetMediaFoundationRenderingMode(mode);