Godot 4.5 GDExtension video player using FFmpeg with D3D11VA hardware decoding on Windows.
Current display path:
FFmpeg demux
-> D3D11VA decoder when available
-> av_hwframe_transfer_data to CPU frame
-> sws_scale to RGBA
-> ImageTexture update in Godot
Prerequisites:
- Godot 4.5 compatible
godot-cppcheckout - FFmpeg shared Windows build with headers and import libraries
- Visual Studio C++ toolchain
- SCons
Current FFmpeg version:
ffmpeg 8.1.1-full_build
libavcodec 62
libavformat 62
libavutil 60
libswscale 9
libswresample 6
Example:
cd addons\hw_video_player
scons godot_cpp_path=<path-to-godot-cpp>Development-only compile-time diagnostics can be enabled explicitly with the SCons boolean option dev_build=yes:
scons godot_cpp_path=<path-to-godot-cpp> dev_build=yesRuntime FFmpeg DLLs are copied into bin/windows-x86_64 via scripts/copy_ffmpeg_runtime.ps1.
Per-frame and periodic performance logs are only printed when built with dev_build=yes. Use get_perf_text() from script when you need runtime performance data in normal builds.
Add HWVideoPlayer node to a scene, set source_path to a local video file, then call play().
Common controls:
$HWVideoPlayer.source_path = "res://videos/example.mp4"
$HWVideoPlayer.play()
$HWVideoPlayer.pause()
$HWVideoPlayer.seek(12.5)
$HWVideoPlayer.stop()Useful properties:
autoplay: Open and playsource_pathwhen the node is ready.loop: Restart automatically when playback reaches the end.prefer_hardware: Prefer D3D11VA hardware decoding when available.keep_aspect: Preserve video aspect ratio when drawing.speed_scale: Playback speed multiplier.
Signals:
started: Emitted after playback successfully starts or resumes.paused: Emitted whenpause()is called.stopped: Emitted whenstop()is called.finished: Emitted when playback reaches the end andloopis disabled.looped: Emitted when playback reaches the end andloopis enabled.seeked(seconds): Emitted after an explicitseek(seconds)call.
Signal registration example:
@onready var player: HWVideoPlayer = $HWVideoPlayer
func _ready() -> void:
player.started.connect(_on_video_started)
player.paused.connect(_on_video_paused)
player.stopped.connect(_on_video_stopped)
player.finished.connect(_on_video_finished)
player.looped.connect(_on_video_looped)
player.seeked.connect(_on_video_seeked)
func _on_video_started() -> void:
print("video started")
func _on_video_paused() -> void:
print("video paused")
func _on_video_stopped() -> void:
print("video stopped")
func _on_video_finished() -> void:
print("video finished")
func _on_video_looped() -> void:
print("video looped")
func _on_video_seeked(seconds: float) -> void:
print("video seeked to ", seconds)Enable the plugin in project.godot:
[editor_plugins]
enabled=PackedStringArray("res://addons/hw_video_player/plugin.cfg")Do not commit generated SCons/MSVC build files such as *.obj.import; they are ignored by .gitignore.