Skip to content

Commit

Permalink
Updates VideoDecoder plugin API to GDExtension.
Browse files Browse the repository at this point in the history
Adds VideoStream and relevant resource loaders to migrate
external GDNative plugins to GDExtension.

Adds a VideoStreamLoader as a specialization of ResourceFormatLoader
as ClassDB::is_parent_class is inaccessible from GDExtension currently.

Using Object* instead of Ref<T> in order to avoid the refcount bug
(godotengine/godot-cpp#652)
Also another bug is in ResourceLoader in use on the extension side that
requires fixing.
  • Loading branch information
kidrigger authored and Streq committed Feb 9, 2023
1 parent d979aff commit d047bb6
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 81 deletions.
14 changes: 14 additions & 0 deletions doc/classes/VideoStream.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,18 @@
</description>
<tutorials>
</tutorials>
<methods>
<method name="_instantiate_playback" qualifiers="virtual">
<return type="VideoStreamPlayback" />
<description>
Called when the video starts playing, to initialize and return a subclass of [VideoStreamPlayback].
</description>
</method>
</methods>
<members>
<member name="file" type="String" setter="set_file" getter="get_file" default="&quot;&quot;">
The video file path or URI that this [VideoStream] resource handles.
For [VideoStreamTheora], this filename should be an Ogg Theora video file with the [code].ogv[/code] extension.
</member>
</members>
</class>
104 changes: 104 additions & 0 deletions doc/classes/VideoStreamPlayback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VideoStreamPlayback" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Internal class used by [VideoStream] to manage playback state when played from a [VideoStreamPlayer].
</brief_description>
<description>
This class is intended to be overridden by video decoder extensions with custom implementations of [VideoStream].
</description>
<tutorials>
</tutorials>
<methods>
<method name="_get_channels" qualifiers="virtual const">
<return type="int" />
<description>
Returns the number of audio channels.
</description>
</method>
<method name="_get_length" qualifiers="virtual const">
<return type="float" />
<description>
Returns the video duration in seconds, if known, or 0 if unknown.
</description>
</method>
<method name="_get_mix_rate" qualifiers="virtual const">
<return type="int" />
<description>
Returns the audio sample rate used for mixing.
</description>
</method>
<method name="_get_playback_position" qualifiers="virtual const">
<return type="float" />
<description>
Return the current playback timestamp. Called in response to the [member VideoStreamPlayer.stream_position] getter.
</description>
</method>
<method name="_get_texture" qualifiers="virtual const">
<return type="Texture2D" />
<description>
Allocates a [Texture2D] in which decoded video frames will be drawn.
</description>
</method>
<method name="_is_paused" qualifiers="virtual const">
<return type="bool" />
<description>
Returns the paused status, as set by [method _set_paused].
</description>
</method>
<method name="_is_playing" qualifiers="virtual const">
<return type="bool" />
<description>
Returns the playback state, as determined by calls to [method _play] and [method _stop].
</description>
</method>
<method name="_play" qualifiers="virtual">
<return type="void" />
<description>
Called in response to [member VideoStreamPlayer.autoplay] or [method VideoStreamPlayer.play]. Note that manual playback may also invoke [method _stop] multiple times before this method is called. [method _is_playing] should return true once playing.
</description>
</method>
<method name="_seek" qualifiers="virtual">
<return type="void" />
<param index="0" name="time" type="float" />
<description>
Seeks to [code]time[/code] seconds. Called in response to the [member VideoStreamPlayer.stream_position] setter.
</description>
</method>
<method name="_set_audio_track" qualifiers="virtual">
<return type="void" />
<param index="0" name="idx" type="int" />
<description>
Select the audio track [code]idx[/code]. Called when playback starts, and in response to the [member VideoStreamPlayer.audio_track] setter.
</description>
</method>
<method name="_set_paused" qualifiers="virtual">
<return type="void" />
<param index="0" name="paused" type="bool" />
<description>
Set the paused status of video playback. [method _is_paused] must return [code]paused[/code]. Called in response to the [member VideoStreamPlayer.paused] setter.
</description>
</method>
<method name="_stop" qualifiers="virtual">
<return type="void" />
<description>
Stops playback. May be called multiple times before [method _play], or in response to [method VideoStreamPlayer.stop]. [method _is_playing] should return false once stopped.
</description>
</method>
<method name="_update" qualifiers="virtual">
<return type="void" />
<param index="0" name="delta" type="float" />
<description>
Ticks video playback for [code]delta[/code] seconds. Called every frame as long as [method _is_paused] and [method _is_playing] return true.
</description>
</method>
<method name="mix_audio">
<return type="int" />
<param index="0" name="num_frames" type="int" />
<param index="1" name="buffer" type="PackedFloat32Array" default="PackedFloat32Array()" />
<param index="2" name="offset" type="int" default="0" />
<description>
Render [code]num_frames[/code] audio frames (of [method _get_channels] floats each) from [code]buffer[/code], starting from index [code]offset[/code] in the array. Returns the number of audio frames rendered, or -1 on error.
</description>
</method>
</methods>
</class>
15 changes: 0 additions & 15 deletions modules/theora/doc_classes/VideoStreamTheora.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,4 @@
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_file">
<return type="String" />
<description>
Returns the Ogg Theora video file handled by this [VideoStreamTheora].
</description>
</method>
<method name="set_file">
<return type="void" />
<param index="0" name="file" type="String" />
<description>
Sets the Ogg Theora video file that this [VideoStreamTheora] resource handles. The [code]file[/code] name should have the [code].ogv[/code] extension.
</description>
</method>
</methods>
</class>
31 changes: 2 additions & 29 deletions modules/theora/video_stream_theora.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,25 +574,10 @@ bool VideoStreamPlaybackTheora::is_paused() const {
return paused;
}

void VideoStreamPlaybackTheora::set_loop(bool p_enable) {
}

bool VideoStreamPlaybackTheora::has_loop() const {
return false;
}

double VideoStreamPlaybackTheora::get_length() const {
return 0;
}

String VideoStreamPlaybackTheora::get_stream_name() const {
return "";
}

int VideoStreamPlaybackTheora::get_loop_count() const {
return 0;
}

double VideoStreamPlaybackTheora::get_playback_position() const {
return get_time();
}
Expand All @@ -601,11 +586,6 @@ void VideoStreamPlaybackTheora::seek(double p_time) {
WARN_PRINT_ONCE("Seeking in Theora videos is not implemented yet (it's only supported for GDExtension-provided video streams).");
}

void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) {
mix_callback = p_callback;
mix_udata = p_userdata;
}

int VideoStreamPlaybackTheora::get_channels() const {
return vi.channels;
}
Expand Down Expand Up @@ -657,16 +637,9 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() {
memdelete(thread_sem);
#endif
clear();
}

void VideoStreamTheora::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamTheora::set_file);
ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamTheora::get_file);

ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file");
}
};

////////////
void VideoStreamTheora::_bind_methods() {}

Ref<Resource> ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
Expand Down
15 changes: 0 additions & 15 deletions modules/theora/video_stream_theora.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {

Ref<ImageTexture> texture;

AudioMixCallback mix_callback = nullptr;
void *mix_udata = nullptr;
bool paused = false;

#ifdef THEORA_USE_THREAD_STREAMING
Expand Down Expand Up @@ -133,15 +131,8 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
virtual void set_paused(bool p_paused) override;
virtual bool is_paused() const override;

virtual void set_loop(bool p_enable) override;
virtual bool has_loop() const override;

virtual double get_length() const override;

virtual String get_stream_name() const;

virtual int get_loop_count() const;

virtual double get_playback_position() const override;
virtual void seek(double p_time) override;

Expand All @@ -150,7 +141,6 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
virtual Ref<Texture2D> get_texture() const override;
virtual void update(double p_delta) override;

virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) override;
virtual int get_channels() const override;
virtual int get_mix_rate() const override;

Expand All @@ -163,9 +153,6 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
class VideoStreamTheora : public VideoStream {
GDCLASS(VideoStreamTheora, VideoStream);

String file;
int audio_track;

protected:
static void _bind_methods();

Expand All @@ -177,8 +164,6 @@ class VideoStreamTheora : public VideoStream {
return pb;
}

void set_file(const String &p_file) { file = p_file; }
String get_file() { return file; }
void set_audio_track(int p_track) override { audio_track = p_track; }

VideoStreamTheora() { audio_track = 0; }
Expand Down
7 changes: 6 additions & 1 deletion scene/gui/video_stream_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,6 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
AudioServer::get_singleton()->unlock();

if (!playback.is_null()) {
playback->set_loop(loops);
playback->set_paused(paused);
texture = playback->get_texture();

Expand Down Expand Up @@ -344,6 +343,12 @@ int VideoStreamPlayer::get_buffering_msec() const {

void VideoStreamPlayer::set_audio_track(int p_track) {
audio_track = p_track;
if (stream.is_valid()) {
stream->set_audio_track(audio_track);
}
if (playback.is_valid()) {
playback->set_audio_track(audio_track);
}
}

int VideoStreamPlayer::get_audio_track() const {
Expand Down
1 change: 0 additions & 1 deletion scene/gui/video_stream_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class VideoStreamPlayer : public Control {
float volume = 1.0;
double last_audio_time = 0.0;
bool expand = false;
bool loops = false;
int buffering_ms = 500;
int audio_track = 0;
int bus_index = 0;
Expand Down
3 changes: 2 additions & 1 deletion scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ void register_scene_types() {

GDREGISTER_CLASS(LineEdit);
GDREGISTER_CLASS(VideoStreamPlayer);
GDREGISTER_VIRTUAL_CLASS(VideoStreamPlayback);
GDREGISTER_VIRTUAL_CLASS(VideoStream);

#ifndef ADVANCED_GUI_DISABLED
GDREGISTER_CLASS(FileDialog);
Expand Down Expand Up @@ -906,7 +908,6 @@ void register_scene_types() {
#ifndef _3D_DISABLED
GDREGISTER_CLASS(AudioStreamPlayer3D);
#endif
GDREGISTER_ABSTRACT_CLASS(VideoStream);
GDREGISTER_CLASS(AudioStreamWAV);
GDREGISTER_CLASS(AudioStreamPolyphonic);
GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackPolyphonic);
Expand Down
Loading

0 comments on commit d047bb6

Please sign in to comment.