diff --git a/CMakeLists.txt b/CMakeLists.txt index f23e2ad..e435263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,8 +72,8 @@ target_sources(${LIBNAME} PRIVATE src/register_types.cpp src/register_types.h - src/filevideostream_class.cpp - src/filevideostream_class.h + src/gdvapivideostream_class.cpp + src/gdvapivideostream_class.h ) # Fetch a list of the xml files to use for documentation and add to our target diff --git a/flake.nix b/flake.nix index 5444da1..2a5e387 100644 --- a/flake.nix +++ b/flake.nix @@ -14,6 +14,11 @@ python3 godot pkg-config + + gst_all_1.gstreamer + gst_all_1.gst-plugins-base + gst_all_1.gst-plugins-good + gst_all_1.gst-plugins-bad ]; buildInputs = with pkgs; [ diff --git a/project/bin/gdvapi.gdextension b/project/bin/gdvapi.gdextension index 93c793f..79a554c 100644 --- a/project/bin/gdvapi.gdextension +++ b/project/bin/gdvapi.gdextension @@ -3,4 +3,5 @@ entry_symbol = "gdvapi_library_init" compatibility_minimum = "4.7" [libraries] -linux.x86_64 = "res://bin/linux/gdvapi.linux.template_debug.x86_64.so" +linux.editor.x86_64 = "res://bin/linux/gdvapi.linux.editor.x86_64.so" +linux.template_debug.x86_64 = "res://bin/linux/gdvapi.linux.template_debug.x86_64.so" diff --git a/project/example.gd b/project/example.gd index d3c0927..ae667dc 100644 --- a/project/example.gd +++ b/project/example.gd @@ -2,4 +2,5 @@ extends Node func _ready() -> void: - $FileVideoStream.begin("res://badapple.mov") + #$GDVAPIVideoStream.begin("udp://0.0.0.0:5000") + pass diff --git a/project/example.tscn b/project/example.tscn index 52249f1..aab50ac 100644 --- a/project/example.tscn +++ b/project/example.tscn @@ -5,4 +5,6 @@ [node name="Node" type="Node" unique_id=2080300232] script = ExtResource("1_jdh55") -[node name="FileVideoStream" type="FileVideoStream" parent="." unique_id=330752336] +[node name="GDVAPIVideoStream" type="GDVAPIVideoStream" parent="." unique_id=1053894928] +offset_right = 40.0 +offset_bottom = 40.0 diff --git a/project/export_presets.cfg b/project/export_presets.cfg new file mode 100644 index 0000000..32df529 --- /dev/null +++ b/project/export_presets.cfg @@ -0,0 +1,49 @@ +[runnable_presets] + +Linux="Linux" + +[preset.0] + +name="Linux" +platform="Linux" +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="exports/godot cpp template.x86_64" +patches=PackedStringArray() +patch_delta_encoding=false +patch_delta_compression_level_zstd=19 +patch_delta_min_reduction=0.1 +patch_delta_include_filters="*" +patch_delta_exclude_filters="" +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_wrapper=1 +binary_format/embed_pck=false +texture_format/s3tc_bptc=true +texture_format/etc2_astc=false +shader_baker/enabled=false +binary_format/architecture="x86_64" +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="#!/usr/bin/env bash +export DISPLAY=:0 +unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" +\"{temp_dir}/{exe_name}\" {cmd_args}" +ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash +pkill -x -f \"{temp_dir}/{exe_name} {cmd_args}\" +rm -rf \"{temp_dir}\"" diff --git a/project/exports/badapple.mov b/project/exports/badapple.mov new file mode 100644 index 0000000..73bab02 Binary files /dev/null and b/project/exports/badapple.mov differ diff --git a/project/exports/godot cpp template.pck b/project/exports/godot cpp template.pck new file mode 100644 index 0000000..9b41a77 Binary files /dev/null and b/project/exports/godot cpp template.pck differ diff --git a/project/exports/godot cpp template.sh b/project/exports/godot cpp template.sh new file mode 100755 index 0000000..dd5bc58 --- /dev/null +++ b/project/exports/godot cpp template.sh @@ -0,0 +1,4 @@ +#!/bin/sh +printf '\033c\033]0;%s\a' godot cpp template +base_path="$(dirname "$(realpath "$0")")" +"$base_path/godot cpp template.x86_64" "$@" diff --git a/project/exports/godot cpp template.x86_64 b/project/exports/godot cpp template.x86_64 new file mode 100755 index 0000000..ff8f2a6 Binary files /dev/null and b/project/exports/godot cpp template.x86_64 differ diff --git a/project/project.godot b/project/project.godot index c22533f..2d39b3e 100644 --- a/project/project.godot +++ b/project/project.godot @@ -18,3 +18,8 @@ config/name="godot cpp template" run/main_scene="uid://dh0oj81pufivs" config/features=PackedStringArray("4.7", "Forward Plus") config/icon="res://icon.svg" + +[display] + +window/size/viewport_width=1920 +window/size/viewport_height=1080 diff --git a/server-ffmpeg.sh b/server-ffmpeg.sh new file mode 100755 index 0000000..c987bb8 --- /dev/null +++ b/server-ffmpeg.sh @@ -0,0 +1,2 @@ +#!/bin/sh +ffmpeg -re -i $1 -c copy -f mpegts udp://127.0.0.1:5000 diff --git a/server-gst.sh b/server-gst.sh new file mode 100644 index 0000000..a740586 --- /dev/null +++ b/server-gst.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +gst-launch-1.0 filesrc location=$1 ! qtdemux name=demux \ + demux.video_0 ! queue ! h264parse ! mpegtsmux name=mux ! udpsink host=127.0.0.1 port=5000 \ + demux.audio_0 ! queue ! aacparse ! mux. diff --git a/server_camera.sh b/server_camera.sh new file mode 100755 index 0000000..cd94f0b --- /dev/null +++ b/server_camera.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -framerate 30 -i "$1" \ + -c:v libx264 -preset ultrafast -tune zerolatency -g 30 -flags +global_header \ + -f mpegts udp://127.0.0.1:5000?pkt_size=1316 diff --git a/src/filevideostream_class.cpp b/src/gdvapivideostream_class.cpp similarity index 79% rename from src/filevideostream_class.cpp rename to src/gdvapivideostream_class.cpp index a09a6cd..2630a97 100644 --- a/src/filevideostream_class.cpp +++ b/src/gdvapivideostream_class.cpp @@ -1,10 +1,12 @@ -#include "filevideostream_class.h" +#include "gdvapivideostream_class.h" #include "godot_cpp/classes/project_settings.hpp" #include "godot_cpp/classes/rd_texture_format.hpp" #include "godot_cpp/classes/rd_texture_view.hpp" #include "godot_cpp/classes/rendering_device.hpp" #include "godot_cpp/classes/rendering_server.hpp" #include "godot_cpp/variant/utility_functions.hpp" +#include "godot_cpp/variant/color.hpp" +#include "godot_cpp/variant/rect2.hpp" extern "C" { #include @@ -21,10 +23,20 @@ enum HWMode { HW_NONE, HW_VAAPI }; static HWMode active_hw_mode = HW_NONE; -void FileVideoStream::_bind_methods() { - godot::ClassDB::bind_method(D_METHOD("begin", "source"), &FileVideoStream::begin); +void GDVAPIVideoStream::_bind_methods() { + godot::ClassDB::bind_method(D_METHOD("begin", "source"), &GDVAPIVideoStream::begin); + + ClassDB::bind_method(D_METHOD("get_desired_width"), &GDVAPIVideoStream::get_desired_width); + ClassDB::bind_method(D_METHOD("set_desired_width", "v"), &GDVAPIVideoStream::set_desired_width); + + ClassDB::bind_method(D_METHOD("get_desired_height"), &GDVAPIVideoStream::get_desired_height); + ClassDB::bind_method(D_METHOD("set_desired_height", "v"), &GDVAPIVideoStream::set_desired_height); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "desired_width"), "set_desired_width", "get_desired_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "desired_height"), "set_desired_height", "get_desired_height"); } + static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *formats) { for (const enum AVPixelFormat *p = formats; *p != -1; p++) { if (active_hw_mode == HW_VULKAN && *p == AV_PIX_FMT_VULKAN) { @@ -39,7 +51,7 @@ static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelF return AV_PIX_FMT_NONE; } -void FileVideoStream::begin(const Variant &source) { +void GDVAPIVideoStream::begin(const Variant &source) { String res_path = source; String global_path = ProjectSettings::get_singleton()->globalize_path(res_path); CharString path_utf8 = global_path.utf8(); @@ -120,7 +132,7 @@ void FileVideoStream::begin(const Variant &source) { set_process(true); } -void FileVideoStream::_process(double delta) { +void GDVAPIVideoStream::_process(double delta) { if (!fmt_ctx || !codec_ctx) return; time_accumulator += delta; @@ -182,11 +194,11 @@ void FileVideoStream::_process(double delta) { } } -FileVideoStream::~FileVideoStream() { +GDVAPIVideoStream::~GDVAPIVideoStream() { cleanup(); } -void FileVideoStream::_notification(int p_what) { +void GDVAPIVideoStream::_notification(int p_what) { switch (p_what) { case NOTIFICATION_EXIT_TREE: { cleanup(); @@ -194,7 +206,7 @@ void FileVideoStream::_notification(int p_what) { } } -void FileVideoStream::texture_init() { +void GDVAPIVideoStream::texture_init() { RenderingDevice *rd = RenderingServer::get_singleton()->get_rendering_device(); if (!rd) return; @@ -232,7 +244,7 @@ void FileVideoStream::texture_init() { } } -void FileVideoStream::cleanup() { +void GDVAPIVideoStream::cleanup() { set_process(false); RenderingDevice *rd = RenderingServer::get_singleton()->get_rendering_device(); @@ -268,8 +280,45 @@ void FileVideoStream::cleanup() { } } -void FileVideoStream::_draw() { +void GDVAPIVideoStream::_draw() { + UtilityFunctions::print("_draw called"); if (godot_texture.is_valid()) { draw_texture(godot_texture, Point2(0, 0)); + } else { + Rect2 rect = Rect2(0, 0, desiredWidth, desiredHeight); + + Color color = Color(1.0, 1.0, 1.0, 1.0); + + draw_rect(rect, color); } } + +void GDVAPIVideoStream::set_desired_width(const int v) { + if (desiredWidth != v) { + desiredWidth = v; + queue_redraw(); + } +} + +void GDVAPIVideoStream::set_desired_height(const int v) { + if (desiredHeight != v) { + desiredHeight = v; + queue_redraw(); + } +} + + +int GDVAPIVideoStream::get_desired_width() const { + return desiredWidth; +} + +int GDVAPIVideoStream::get_desired_height() const { + return desiredHeight; +} + + + +void GDVAPIVideoStream::_ready() { + UtilityFunctions::print("_ready called"); + queue_redraw(); +} diff --git a/src/filevideostream_class.h b/src/gdvapivideostream_class.h similarity index 71% rename from src/filevideostream_class.h rename to src/gdvapivideostream_class.h index d17a78a..b06e371 100644 --- a/src/filevideostream_class.h +++ b/src/gdvapivideostream_class.h @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include "godot_cpp/classes/control.hpp" #include "godot_cpp/classes/texture2drd.hpp" @@ -13,8 +13,8 @@ extern "C" { namespace godot { -class FileVideoStream : public Control { - GDCLASS(FileVideoStream, Control) +class GDVAPIVideoStream : public Control { + GDCLASS(GDVAPIVideoStream, Control) private: AVFormatContext *fmt_ctx = nullptr; @@ -35,6 +35,10 @@ private: RID texture_rd_rid; Ref godot_texture; + + int desiredWidth = 256; + int desiredHeight = 256; + void cleanup(); void texture_init(); @@ -42,8 +46,8 @@ protected: static void _bind_methods(); public: - FileVideoStream() = default; - ~FileVideoStream() override; + GDVAPIVideoStream() = default; + ~GDVAPIVideoStream() override; void begin(const Variant &source); @@ -51,6 +55,13 @@ public: void _notification(int p_what); void _draw() override; + void _ready() override; + + void set_desired_width(const int v); + int get_desired_width() const; + + void set_desired_height(const int v); + int get_desired_height() const; }; } diff --git a/src/register_types.cpp b/src/register_types.cpp index bc51a55..37ad78c 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -5,7 +5,7 @@ #include #include -#include "filevideostream_class.h" +#include "gdvapivideostream_class.h" using namespace godot; @@ -13,9 +13,11 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - GDREGISTER_CLASS(FileVideoStream); + + GDREGISTER_RUNTIME_CLASS(GDVAPIVideoStream); } + void uninitialize_gdextension_types(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; @@ -23,7 +25,6 @@ void uninitialize_gdextension_types(ModuleInitializationLevel p_level) { } extern "C" { -// Initialization GDExtensionBool GDE_EXPORT gdvapi_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) { GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); init_obj.register_initializer(initialize_gdextension_types);