Updated GDE GoZen

Updated GDE GoZen to 9.2 (Custom Linux build for Transparent VP9 Video)
This commit is contained in:
Mario Steele 2026-03-02 01:59:33 -06:00
parent 76ba9536b7
commit e4637479e9
15 changed files with 27 additions and 42 deletions

View file

@ -9,6 +9,9 @@ To see video files in your projects file tree, you need to add `mp4` and any oth
1. When exporting, you'll have your executable and the GDE GoZen library file, these do need to be both shared for the application to work. 1. When exporting, you'll have your executable and the GDE GoZen library file, these do need to be both shared for the application to work.
2. Also, you will have to add `*.mp4` and other extension names of your video files to the resources which need to get exported for each platform you want to export for, otherwise your video files will not be included in your final export. 2. Also, you will have to add `*.mp4` and other extension names of your video files to the resources which need to get exported for each platform you want to export for, otherwise your video files will not be included in your final export.
## Android (SAF)
Due to the way SAF works (Godot 4.6+), accessing files through the browser might give invalid paths. You need to be certain you get the absolute path instead. Inside of the `test_room` you can find an example of how this is done for Android, by basically copying the videos to a temporary folder which will give an absolute path. Only thing to be careful of is to also remove the data afterwards out of the temporary folder.
## Help needed? ## Help needed?
You can go to the [GitHub repo](https://github.com/VoylinsGamedevJourney/gde_gozen/issues) to report problems, or visit out [Discord server](discord.gg/BdbUf7VKYC) for help/advice. You can go to the [GitHub repo](https://github.com/VoylinsGamedevJourney/gde_gozen/issues) to report problems, or visit out [Discord server](discord.gg/BdbUf7VKYC) for help/advice.

View file

@ -2,7 +2,7 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bijjjb1qmqf7f" uid="uid://dcpha8teexb00"
path="res://.godot/imported/icon.svg-ac53c9c419a88eda808214a4d44243c3.ctex" path="res://.godot/imported/icon.svg-ac53c9c419a88eda808214a4d44243c3.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false

View file

@ -2,7 +2,7 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dbk4jierdjfrf" uid="uid://bndqydg778xif"
path="res://.godot/imported/icon.webp-a5a23a9a73b8ba8140cf260e6bfffac7.ctex" path="res://.godot/imported/icon.webp-a5a23a9a73b8ba8140cf260e6bfffac7.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false

View file

@ -3,5 +3,5 @@
name="gde_gozen" name="gde_gozen"
description="Providing performant video playback." description="Providing performant video playback."
author="Voylin's Gamedev Journey" author="Voylin's Gamedev Journey"
version="v9.1" version="v9.2"
script="plugin.gd" script="plugin.gd"

View file

@ -107,11 +107,9 @@ func _exit_tree() -> void:
# Making certain no remaining tasks are running in separate threads. # Making certain no remaining tasks are running in separate threads.
if _video_thread != -1: if _video_thread != -1:
var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread) var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread)
if error != OK: if error != OK:
printerr("Something went wrong waiting for task completion! %s" % error) printerr("Something went wrong waiting for task completion! %s" % error)
_video_thread = -1 _video_thread = -1
if video != null: if video != null:
close() close()
@ -129,7 +127,6 @@ func _ready() -> void:
func set_video_path(new_path: String) -> void: func set_video_path(new_path: String) -> void:
if video != null: if video != null:
close() close()
if !is_node_ready(): if !is_node_ready():
await ready await ready
if !get_tree().root.is_node_ready(): if !get_tree().root.is_node_ready():
@ -144,24 +141,25 @@ func set_video_path(new_path: String) -> void:
path = new_path path = new_path
video = GoZenVideo.new() video = GoZenVideo.new()
if debug: if debug:
video.enable_debug() video.enable_debug()
else: else:
video.disable_debug() video.disable_debug()
_video_thread = WorkerThreadPool.add_task(_open_video) _video_thread = WorkerThreadPool.add_task(_open_video)
if enable_audio: if enable_audio:
_open_audio() _open_audio()
## Update the video manually by providing a GoZenVideo instance and an optional AudioStreamWAV. ## Update the video manually by providing a GoZenVideo instance and an optional AudioStreamWAV.
func update_video(video_instance: GoZenVideo) -> void: func update_video(video_instance: GoZenVideo, audio_stream: AudioStreamWAV = null) -> void:
if video != null: if video != null:
close() close()
path = video_instance.get_path()
_update_video(video_instance) _update_video(video_instance)
if audio_stream:
audio_player.stream = audio_stream
else:
_open_audio() _open_audio()
@ -206,7 +204,6 @@ func _update_video(new_video: GoZenVideo) -> void:
image = Image.create_empty(_resolution.x, _resolution.y, false, Image.FORMAT_R8) image = Image.create_empty(_resolution.x, _resolution.y, false, Image.FORMAT_R8)
image.fill(Color.WHITE) image.fill(Color.WHITE)
if debug: if debug:
_print_video_debug() _print_video_debug()
@ -240,7 +237,6 @@ func _set_color_profile(new_profile: COLOR_PROFILE = color_profile) -> void:
var profile_str: String = video.get_color_profile() var profile_str: String = video.get_color_profile()
color_profile = new_profile color_profile = new_profile
if new_profile != COLOR_PROFILE.AUTO: if new_profile != COLOR_PROFILE.AUTO:
profile_str = str(COLOR_PROFILE.find_key(COLOR_PROFILE.BT2100)).to_lower() profile_str = str(COLOR_PROFILE.find_key(COLOR_PROFILE.BT2100)).to_lower()
@ -248,7 +244,6 @@ func _set_color_profile(new_profile: COLOR_PROFILE = color_profile) -> void:
"bt2020", "bt2100": color_data = Vector4(1.4746, 0.16455, 0.57135, 1.8814) "bt2020", "bt2100": color_data = Vector4(1.4746, 0.16455, 0.57135, 1.8814)
"bt601", "bt470": color_data = Vector4(1.402, 0.344136, 0.714136, 1.772) "bt601", "bt470": color_data = Vector4(1.402, 0.344136, 0.714136, 1.772)
_: color_data = Vector4(1.5748, 0.1873, 0.4681, 1.8556) # bt709 and unknown _: color_data = Vector4(1.5748, 0.1873, 0.4681, 1.8556) # bt709 and unknown
_shader_material.set_shader_parameter("color_profile", color_data) _shader_material.set_shader_parameter("color_profile", color_data)
@ -282,7 +277,6 @@ func close() -> void:
if video != null: if video != null:
if is_playing: if is_playing:
pause() pause()
video = null video = null
@ -291,7 +285,6 @@ func _process(delta: float) -> void:
if is_playing: if is_playing:
_skips = 0 _skips = 0
_time_elapsed += delta _time_elapsed += delta
if _time_elapsed < _frame_time: if _time_elapsed < _frame_time:
return return
@ -302,39 +295,36 @@ func _process(delta: float) -> void:
if current_frame >= _frame_count: if current_frame >= _frame_count:
is_playing = !is_playing is_playing = !is_playing
if enable_audio and audio_player.stream != null: if enable_audio and audio_player.stream != null:
audio_player.set_stream_paused(true) audio_player.set_stream_paused(true)
video_ended.emit() video_ended.emit()
if loop: if loop:
seek_frame(0) seek_frame(0)
play() play()
else: else:
_sync_audio_video() _sync_audio_video()
while _skips != 1: while _skips != 1:
next_frame(true) next_frame(true)
_skips -= 1 _skips -= 1
next_frame() next_frame()
elif _video_thread != -1: elif _video_thread != -1:
var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread) var error: int = WorkerThreadPool.wait_for_task_completion(_video_thread)
if error != OK: if error != OK:
printerr("Something went wrong waiting for task completion! %s" % error) printerr("Something went wrong waiting for task completion! %s" % error)
_video_thread = -1 _video_thread = -1
_update_video(video) _update_video(video)
if enable_auto_play: if enable_auto_play:
play() play()
## Start the video playback. This will play until reaching the end of the video and then pause and go back to the start. ## Start the video playback. This will play until reaching the end of the video and then pause and go back to the start.
func play() -> void: func play() -> void:
if video != null and !is_open() and is_playing: if not is_open():
print("The video on '%s' isn't open yet!" % path)
return return
if is_playing: return
is_playing = true is_playing = true
if enable_audio and audio_player.stream.get_length() != 0: if enable_audio and audio_player.stream.get_length() != 0:
@ -348,10 +338,8 @@ func play() -> void:
## Pausing the video. ## Pausing the video.
func pause() -> void: func pause() -> void:
is_playing = false is_playing = false
if enable_audio and audio_player.stream != null: if enable_audio and audio_player.stream != null:
audio_player.set_stream_paused(true) audio_player.set_stream_paused(true)
playback_paused.emit() playback_paused.emit()
@ -361,7 +349,6 @@ func _sync_audio_video() -> void:
return return
elif enable_audio and audio_player.stream.get_length() != 0: elif enable_audio and audio_player.stream.get_length() != 0:
var audio_offset: float = audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate var audio_offset: float = audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate
if abs(audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate) > AUDIO_OFFSET_THRESHOLD: if abs(audio_player.get_playback_position() + AudioServer.get_time_since_last_mix() - (current_frame + 1) / _frame_rate) > AUDIO_OFFSET_THRESHOLD:
if debug: print("Audio Sync: time correction: ", audio_offset) if debug: print("Audio Sync: time correction: ", audio_offset)
audio_player.seek((current_frame + 1) / _frame_rate) audio_player.seek((current_frame + 1) / _frame_rate)
@ -451,7 +438,6 @@ func _set_frame_image() -> void:
RenderingServer.texture_2d_update(y_texture.get_rid(), video.get_y_data(), 0) RenderingServer.texture_2d_update(y_texture.get_rid(), video.get_y_data(), 0)
RenderingServer.texture_2d_update(u_texture.get_rid(), video.get_u_data(), 0) RenderingServer.texture_2d_update(u_texture.get_rid(), video.get_u_data(), 0)
RenderingServer.texture_2d_update(v_texture.get_rid(), video.get_v_data(), 0) RenderingServer.texture_2d_update(v_texture.get_rid(), video.get_v_data(), 0)
if _has_alpha: if _has_alpha:
RenderingServer.texture_2d_update(a_texture.get_rid(), video.get_a_data(), 0) RenderingServer.texture_2d_update(a_texture.get_rid(), video.get_a_data(), 0)
@ -463,7 +449,6 @@ func set_playback_speed(new_playback_value: float) -> void:
if enable_audio and audio_player.stream != null: if enable_audio and audio_player.stream != null:
audio_player.pitch_scale = playback_speed audio_player.pitch_scale = playback_speed
_set_pitch_adjust() _set_pitch_adjust()
if is_playing: if is_playing:
audio_player.play(current_frame * (1.0 / _frame_rate)) audio_player.play(current_frame * (1.0 / _frame_rate))
@ -521,7 +506,7 @@ func _open_audio(stream_id: int = -1) -> void:
printerr("Failed to open AudioStreamFFmpeg for: %s" % path) printerr("Failed to open AudioStreamFFmpeg for: %s" % path)
return return
audio_player.set_stream.call_deferred(stream) audio_player.stream = stream
func _print_stream_info(streams: PackedInt32Array) -> void: func _print_stream_info(streams: PackedInt32Array) -> void:
@ -565,22 +550,19 @@ func _print_video_debug() -> void:
print("Using sws: ", video.is_using_sws()) print("Using sws: ", video.is_using_sws())
print("Sar: ", video.get_sar()) print("Sar: ", video.get_sar())
if video_streams.size() != 0:
print_rich("Video streams: [i](%s)" % video_streams.size()) print_rich("Video streams: [i](%s)" % video_streams.size())
_print_stream_info(video_streams) _print_stream_info(video_streams)
else:
print("No video streams found.")
if audio_streams.size() != 0: if audio_streams.size() != 0:
print_rich("Audio streams: [i](%s)" % audio_streams.size()) print_rich("Audio streams: [i](%s)" % audio_streams.size())
_print_stream_info(audio_streams) _print_stream_info(audio_streams)
else: elif debug:
print("No audio streams found.") print("No audio streams found.")
if subtitle_streams.size() != 0: if subtitle_streams.size() != 0:
print_rich("Subtitle streams: [i](%s)" % subtitle_streams.size()) print_rich("Subtitle streams: [i](%s)" % subtitle_streams.size())
_print_stream_info(subtitle_streams) _print_stream_info(subtitle_streams)
else: elif debug:
print("No subtitle streams found.") print("No subtitle streams found.")
if chapters.size() != 0: if chapters.size() != 0: