You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
Initial GDExtension demo code, which can initialize a Timeline and FFmpegReader instance, print Profiles, and send an Image into Godot 4.4/4.5. This is highly experimental, and disabled by default. Requires ENABLE_GODOT=1 to build, and manually copying the gdextension and bindings/godot/*.so file into your Godot project bin. NOTE: This also required a locally compiled version of Godot and Godot-cpp.
This commit is contained in:
@@ -20,6 +20,10 @@ IF(NOT DEFINED ENABLE_JAVA)
|
||||
SET(ENABLE_JAVA 0)
|
||||
ENDIF()
|
||||
|
||||
IF(NOT DEFINED ENABLE_GODOT)
|
||||
SET(ENABLE_GODOT 0)
|
||||
ENDIF()
|
||||
|
||||
############### INCLUDE EACH LANGUAGE BINDING ################
|
||||
IF (ENABLE_PYTHON)
|
||||
add_subdirectory(python)
|
||||
@@ -32,3 +36,7 @@ ENDIF (ENABLE_RUBY)
|
||||
IF (ENABLE_JAVA)
|
||||
add_subdirectory(java)
|
||||
ENDIF (ENABLE_JAVA)
|
||||
|
||||
IF (ENABLE_GODOT)
|
||||
add_subdirectory(godot)
|
||||
ENDIF (ENABLE_GODOT)
|
||||
35
bindings/godot/CMakeLists.txt
Normal file
35
bindings/godot/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
project(libopenshot_godot)
|
||||
|
||||
# Clone and build GoDot CPP
|
||||
# git submodule add https://github.com/godotengine/godot-cpp.git external/godot-cpp
|
||||
# git submodule update --init --recursive
|
||||
# cd external/godot-cpp
|
||||
# scons -c
|
||||
# scons platform=linux generate_bindings=yes -j$(nproc)
|
||||
set(GODOT_CPP_PATH ${CMAKE_SOURCE_DIR}/external/godot-cpp)
|
||||
|
||||
include_directories(
|
||||
${GODOT_CPP_PATH}/include
|
||||
${GODOT_CPP_PATH}/gen/include
|
||||
${GODOT_CPP_PATH}/gdextension
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
link_directories(${GODOT_CPP_PATH}/bin)
|
||||
|
||||
add_library(libopenshot_godot SHARED
|
||||
register_types.cpp
|
||||
osg_timeline.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(libopenshot_godot
|
||||
${GODOT_CPP_PATH}/bin/libgodot-cpp.linux.template_debug.x86_64.a
|
||||
openshot
|
||||
)
|
||||
|
||||
set_target_properties(libopenshot_godot PROPERTIES
|
||||
OUTPUT_NAME "libopenshot_godot"
|
||||
PREFIX ""
|
||||
)
|
||||
7
bindings/godot/libopenshot_godot.gdextension
Normal file
7
bindings/godot/libopenshot_godot.gdextension
Normal file
@@ -0,0 +1,7 @@
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "example_library_init"
|
||||
compatibility_minimum = "4.1"
|
||||
|
||||
[libraries]
|
||||
linux.debug.x86_64 = "res://bin/libopenshot_godot.so"
|
||||
104
bindings/godot/osg_timeline.cpp
Normal file
104
bindings/godot/osg_timeline.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Source file for Godot wrapper
|
||||
* @author Jonathan Thomas <jonathan@openshot.org>
|
||||
*
|
||||
* @ref License
|
||||
*/
|
||||
|
||||
// Copyright (c) 2008-2025 OpenShot Studios, LLC
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "osg_timeline.h"
|
||||
#include "FFmpegReader.h"
|
||||
#include "Profiles.h"
|
||||
#include "Timeline.h"
|
||||
|
||||
#include "godot_cpp/classes/image.hpp"
|
||||
#include "godot_cpp/classes/image_texture.hpp"
|
||||
#include "godot_cpp/variant/utility_functions.hpp"
|
||||
#include "godot_cpp/core/class_db.hpp"
|
||||
|
||||
using namespace godot;
|
||||
|
||||
void ExampleClass::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("load_file", "path"), &ExampleClass::load_file);
|
||||
ClassDB::bind_method(D_METHOD("print_type", "variant"), &ExampleClass::print_type);
|
||||
ClassDB::bind_method(D_METHOD("print_json"), &ExampleClass::print_json);
|
||||
ClassDB::bind_method(D_METHOD("get_image", "frame_number"), &ExampleClass::get_image);
|
||||
}
|
||||
|
||||
ExampleClass::ExampleClass() {
|
||||
constructor_called = true;
|
||||
print_line("Constructor called!");
|
||||
|
||||
// Create example timeline
|
||||
timeline = new openshot::Timeline(
|
||||
1920, 1080,
|
||||
openshot::Fraction(30, 1),
|
||||
44100, 2,
|
||||
openshot::LAYOUT_STEREO);
|
||||
|
||||
print_line("Timeline instantiated!");
|
||||
}
|
||||
|
||||
ExampleClass::~ExampleClass() {
|
||||
print_line("Destructor called!");
|
||||
delete timeline;
|
||||
timeline = nullptr;
|
||||
delete reader;
|
||||
reader = nullptr;
|
||||
}
|
||||
|
||||
void ExampleClass::load_file(const String path) {
|
||||
if (reader == nullptr)
|
||||
{
|
||||
// Create example reader
|
||||
reader = new openshot::FFmpegReader(path.utf8().get_data(), true);
|
||||
reader->Open();
|
||||
}
|
||||
}
|
||||
|
||||
void ExampleClass::print_type(const Variant &p_variant) const {
|
||||
print_line(vformat("Type: %d", p_variant.get_type()));
|
||||
}
|
||||
|
||||
void ExampleClass::print_json(const Variant &p_variant) {
|
||||
print_line("print_json!");
|
||||
openshot::Profile p("/home/jonathan/apps/openshot-qt/src/profiles/01920x1080p2997_16-09");
|
||||
std::string s = timeline->Json();
|
||||
String output = "OpenShot Profile JSON: " + String(s.c_str());
|
||||
UtilityFunctions::print(output);
|
||||
}
|
||||
|
||||
Ref<Image> ExampleClass::get_image(const int64_t frame_number) {
|
||||
if (reader && reader->IsOpen())
|
||||
{
|
||||
// Load video frame
|
||||
auto frame = reader->GetFrame(frame_number);
|
||||
std::shared_ptr<QImage> qimg = frame->GetImage();
|
||||
|
||||
// Convert ARGB32_Premultiplied to RGBA8888, keeping premultiplied alpha
|
||||
QImage rgba_image = qimg->convertToFormat(QImage::Format_RGBA8888);
|
||||
|
||||
// Copy pixel data
|
||||
int width = rgba_image.width();
|
||||
int height = rgba_image.height();
|
||||
PackedByteArray buffer;
|
||||
buffer.resize(width * height * 4);
|
||||
memcpy(buffer.ptrw(), rgba_image.constBits(), buffer.size());
|
||||
|
||||
// Create Godot Image
|
||||
Ref<Image> image = Image::create(width, height, false, Image::FORMAT_RGBA8);
|
||||
image->set_data(width, height, false, Image::FORMAT_RGBA8, buffer);
|
||||
|
||||
print_line(vformat("✅ Image created: %dx%d (premultiplied alpha)", width, height));
|
||||
return image;
|
||||
}
|
||||
|
||||
// Empty image
|
||||
return Ref<Image>();
|
||||
}
|
||||
|
||||
|
||||
42
bindings/godot/osg_timeline.h
Normal file
42
bindings/godot/osg_timeline.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Header file for Godot wrapper
|
||||
* @author Jonathan Thomas <jonathan@openshot.org>
|
||||
*
|
||||
* @ref License
|
||||
*/
|
||||
|
||||
// Copyright (c) 2008-2025 OpenShot Studios, LLC
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "godot_cpp/classes/ref_counted.hpp"
|
||||
#include "godot_cpp/classes/image.hpp"
|
||||
#include "godot_cpp/variant/variant.hpp"
|
||||
#include "Timeline.h"
|
||||
#include "FFmpegReader.h"
|
||||
|
||||
using namespace godot;
|
||||
|
||||
class ExampleClass : public RefCounted {
|
||||
GDCLASS(ExampleClass, RefCounted)
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
ExampleClass();
|
||||
~ExampleClass() override;
|
||||
|
||||
void load_file(String path);
|
||||
void print_type(const Variant &p_variant) const;
|
||||
void print_json(const Variant &p_variant);
|
||||
Ref<Image> get_image(int64_t frame_number);
|
||||
|
||||
private:
|
||||
openshot::Timeline* timeline = nullptr;
|
||||
openshot::FFmpegReader* reader = nullptr;
|
||||
bool constructor_called = false;
|
||||
};
|
||||
48
bindings/godot/register_types.cpp
Normal file
48
bindings/godot/register_types.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Source file for registering Godot wrapper
|
||||
* @author Jonathan Thomas <jonathan@openshot.org>
|
||||
*
|
||||
* @ref License
|
||||
*/
|
||||
|
||||
// Copyright (c) 2008-2025 OpenShot Studios, LLC
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include "osg_timeline.h"
|
||||
|
||||
using namespace godot;
|
||||
|
||||
void initialize_gdextension_types(godot::ModuleInitializationLevel p_level) {
|
||||
if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) return;
|
||||
|
||||
godot::ClassDB::register_class<ExampleClass>();
|
||||
}
|
||||
|
||||
void uninitialize_gdextension_types(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// Initialization
|
||||
GDExtensionBool GDE_EXPORT example_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);
|
||||
init_obj.register_terminator(uninitialize_gdextension_types);
|
||||
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||
|
||||
return init_obj.init();
|
||||
}
|
||||
}
|
||||
19
bindings/godot/register_types.h
Normal file
19
bindings/godot/register_types.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Header file for registering Godot wrapper
|
||||
* @author Jonathan Thomas <jonathan@openshot.org>
|
||||
*
|
||||
* @ref License
|
||||
*/
|
||||
|
||||
// Copyright (c) 2008-2025 OpenShot Studios, LLC
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef EXAMPLE_REGISTER_TYPES_H
|
||||
#define EXAMPLE_REGISTER_TYPES_H
|
||||
|
||||
void initialize_gdextension_types();
|
||||
void uninitialize_gdextension_types();
|
||||
|
||||
#endif // EXAMPLE_REGISTER_TYPES_H
|
||||
1
external/godot-cpp
vendored
Submodule
1
external/godot-cpp
vendored
Submodule
Submodule external/godot-cpp added at 6388e26dd8
Reference in New Issue
Block a user