#ifndef MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_RENDERER_H_
#define MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_RENDERER_H_
#include <d3d11.h>
#include <mfapi.h>
#include <mfmediaengine.h>
#include <wrl.h>
#include <memory>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "base/win/windows_types.h"
#include "media/base/buffering_state.h"
#include "media/base/media_export.h"
#include "media/base/media_resource.h"
#include "media/base/pipeline_status.h"
#include "media/base/renderer.h"
#include "media/base/renderer_client.h"
#include "media/renderers/win/media_engine_extension.h"
#include "media/renderers/win/media_engine_notify_impl.h"
#include "media/renderers/win/media_foundation_protection_manager.h"
#include "media/renderers/win/media_foundation_renderer_extension.h"
#include "media/renderers/win/media_foundation_source_wrapper.h"
namespace media {
class MediaLog;
class MEDIA_EXPORT MediaFoundationRenderer
: public Renderer,
public MediaFoundationRendererExtension {
public:
enum class ErrorReason {
kUnknown = 0,
kCdmProxyReceivedInInvalidState = 1,
kFailedToSetSourceOnMediaEngine = 2,
kFailedToSetCurrentTime = 3,
kFailedToPlay = 4,
kOnPlaybackError = 5,
kOnDCompSurfaceReceivedError [[deprecated]] = 6,
kOnDCompSurfaceHandleSetError = 7,
kOnConnectionError = 8,
kFailedToSetDCompMode = 9,
kFailedToGetDCompSurface = 10,
kFailedToDuplicateHandle = 11,
kFailedToCreateMediaEngine = 12,
kFailedToCreateDCompTextureWrapper = 13,
kFailedToInitDCompTextureWrapper = 14,
kFailedToSetPlaybackRate = 15,
kFailedToGetMediaEngineEx = 16,
kMaxValue = kFailedToGetMediaEngineEx,
};
enum class RenderedVideoFrameDetectionResult {
kDetected = 1,
kNotDetected = 2,
kUnknownByPlaybackError = 3,
kUnknownByPlaybackEnd = 4,
kUnknownByShutdown = 5,
kMaxValue = kUnknownByShutdown,
};
static void ReportErrorReason(ErrorReason reason);
MediaFoundationRenderer(scoped_refptr<base::SequencedTaskRunner> task_runner,
std::unique_ptr<MediaLog> media_log,
LUID gpu_process_adapter_luid,
bool is_testing = false);
MediaFoundationRenderer(const MediaFoundationRenderer&) = delete;
MediaFoundationRenderer& operator=(const MediaFoundationRenderer&) = delete;
~MediaFoundationRenderer() override;
void Initialize(MediaResource* media_resource,
RendererClient* client,
PipelineStatusCallback init_cb) override;
void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override;
void SetLatencyHint(std::optional<base::TimeDelta> latency_hint) override;
void Flush(base::OnceClosure flush_cb) override;
void StartPlayingFrom(base::TimeDelta time) override;
void SetPlaybackRate(double playback_rate) override;
void SetVolume(float volume) override;
base::TimeDelta GetMediaTime() override;
RendererType GetRendererType() override;
void GetDCompSurface(GetDCompSurfaceCB callback) override;
void SetVideoStreamEnabled(bool enabled) override;
void SetOutputRect(const gfx::Rect& output_rect,
SetOutputRectCB callback) override;
void SetGpuProcessAdapterLuid(LUID gpu_process_adapter_luid);
private:
enum class StopSendingStatisticsReason {
kPlaybackEnded = 0,
kPlaybackPauseInternal = 1,
kPlaybackError = 2,
kShutdown = 3,
kMaxValue = kShutdown,
};
HRESULT CreateMediaEngine(MediaResource* media_resource);
HRESULT InitializeDXGIDeviceManager();
HRESULT InitializeVirtualVideoWindow();
HRESULT PopulateStatistics(PipelineStatistics& statistics);
void SendStatistics();
void StartSendingStatistics();
void StopSendingStatistics(StopSendingStatisticsReason reason);
bool NeedRenderedVideoFrameDetection();
void CheckRenderedVideoFrame(const PipelineStatistics& stats);
void RestartRenderedVideoFrameDetectionTimerInNotReported();
void ReportRenderedVideoFrameDetectionResult(
RenderedVideoFrameDetectionResult result);
void OnPlaybackError(PipelineStatus status, HRESULT hr);
void OnPlaybackEnded();
void OnFormatChange();
void OnLoadedData();
void OnCanPlayThrough();
void OnPlaying();
void OnWaiting();
void OnFrameStepCompleted();
void OnTimeUpdate();
void OnProtectionManagerWaiting(WaitingReason reason);
void OnCdmProxyReceived();
void OnBufferingStateChange(BufferingState state,
BufferingStateChangeReason reason);
HRESULT SetDCompModeInternal();
HRESULT GetDCompSurfaceInternal(HANDLE* surface_handle);
HRESULT SetSourceOnMediaEngine();
HRESULT UpdateVideoStream(const gfx::Size rect_size);
HRESULT PauseInternal();
void OnVideoNaturalSizeChange();
void OnError(PipelineStatus status,
ErrorReason reason,
HRESULT hresult,
PipelineStatusCallback status_cb = base::NullCallback());
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<MediaLog> media_log_;
LUID gpu_process_adapter_luid_;
const bool is_testing_;
raw_ptr<RendererClient> renderer_client_;
Microsoft::WRL::ComPtr<IMFMediaEngine> mf_media_engine_;
Microsoft::WRL::ComPtr<MediaEngineNotifyImpl> mf_media_engine_notify_;
Microsoft::WRL::ComPtr<MediaEngineExtension> mf_media_engine_extension_;
Microsoft::WRL::ComPtr<MediaFoundationSourceWrapper> mf_source_;
Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> dxgi_device_manager_;
gfx::Size current_video_rect_size_;
base::TimeDelta duration_;
gfx::Size native_video_size_;
float volume_ = 1.0;
double playback_rate_ = 0.0;
BufferingState max_buffering_state_ = BufferingState::BUFFERING_HAVE_NOTHING;
PipelineStatistics statistics_ = {};
base::RepeatingTimer statistics_timer_;
int populate_statistics_failure_count_ = 0;
HWND virtual_video_window_ = nullptr;
bool waiting_for_mf_cdm_ = false;
raw_ptr<CdmContext> cdm_context_ = nullptr;
scoped_refptr<MediaFoundationCdmProxy> cdm_proxy_;
Microsoft::WRL::ComPtr<MediaFoundationProtectionManager>
content_protection_manager_;
bool has_reported_playing_ = false;
bool has_reported_significant_playback_ = false;
std::optional<base::TimeDelta> latency_hint_;
bool has_reported_rendered_video_frame_detection_ = false;
std::optional<base::TimeTicks> rendered_video_frame_detection_start_time_;
bool has_reported_multi_gpu_histogram_ = false;
base::WeakPtrFactory<MediaFoundationRenderer> weak_factory_{this};
};
}
#endif