-
Notifications
You must be signed in to change notification settings - Fork 364
OpenFX Module #1186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OpenFX Module #1186
Changes from all commits
f65b098
4681405
bf155f1
b22535b
3709874
bc8798a
bdbbdc5
dea2a02
41c144c
ebd0a1c
02ccdbc
e25a6c9
15f3ac4
912501e
a02a87b
ea99a03
dbfccf2
4b352b4
336a8e0
7ef1edc
06b8a33
5fa2d86
9da20ce
8e8957c
70246fc
fcedd95
9a83112
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| add_library(mltopenfx MODULE | ||
| factory.c | ||
| mlt_openfx.c mlt_openfx.h | ||
| filter_openfx.c | ||
| ) | ||
|
|
||
| add_custom_target(Other_openfx_Files SOURCES | ||
| filter_openfx.yml | ||
| ) | ||
|
|
||
| if(GPL AND TARGET PkgConfig::glib) | ||
| include(GenerateExportHeader) | ||
| generate_export_header(mltopenfx) | ||
| target_compile_options(mltopenfx PRIVATE ${MLT_COMPILE_OPTIONS}) | ||
| target_include_directories(mltopenfx PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) | ||
| target_link_libraries(mltopenfx PRIVATE mlt PkgConfig::glib ${CMAKE_DL_LIBS}) | ||
| if(NOT MSVC) | ||
| target_link_libraries(mltopenfx PRIVATE m) | ||
| endif() | ||
| endif() | ||
|
|
||
| set_target_properties(mltopenfx PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") | ||
|
|
||
| install(TARGETS mltopenfx LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) | ||
|
|
||
| install(FILES filter_openfx.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/openfx) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,312 @@ | ||
| /* | ||
| * factory.c -- the factory method interfaces | ||
| * Copyright (C) 2025 Meltytech, LLC | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; either version 2 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this program; if not, write to the Free Software Foundation, | ||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| */ | ||
|
|
||
| #include "mlt_openfx.h" | ||
| #include <glib.h> | ||
| #include <stdbool.h> | ||
| extern OfxHost MltOfxHost; | ||
| static OfxSetHostFn ofx_set_host; | ||
| static OfxGetPluginFn ofx_get_plugin; | ||
| static OfxGetNumberOfPluginsFn ofx_get_number_of_plugins; | ||
| static int NumberOfPlugins; | ||
| mlt_properties mltofx_context; | ||
| mlt_properties mltofx_dl; | ||
|
|
||
| #if defined(__linux__) || defined(__FreeBSD__) | ||
|
|
||
| #define OFX_DIRLIST_SEP_CHARS ":;" | ||
| #define OFX_DIRSEP "/" | ||
| #include <dirent.h> | ||
|
|
||
| static const char *getArchStr() | ||
| { | ||
| if (sizeof(void *) == 4) { | ||
| #if defined(__linux__) | ||
| return "Linux-x86"; | ||
| #else | ||
| return "FreeBSD-x86"; | ||
| #endif | ||
| } else { | ||
| #if defined(__linux__) | ||
| return "Linux-x86-64"; | ||
| #else | ||
| return "FreeBSD-x86-64"; | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| #define OFX_ARCHSTR getArchStr() | ||
|
|
||
| #elif defined(__APPLE__) | ||
|
|
||
| #define OFX_DIRLIST_SEP_CHARS ";:" | ||
| #if defined(__x86_64) || defined(__x86_64__) | ||
| #define OFX_ARCHSTR "MacOS-x86-64" | ||
| #else | ||
| #define OFX_ARCHSTR "MacOS" | ||
| #endif | ||
| #define OFX_DIRSEP "/" | ||
| #include <dirent.h> | ||
|
|
||
| #elif defined(WINDOWS) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) \ | ||
| || defined(__MINGW64__) | ||
| #define OFX_DIRLIST_SEP_CHARS ";" | ||
| #if defined(_WIN64) || defined(__MINGW64__) | ||
| #define OFX_ARCHSTR "Win64" | ||
| #else | ||
| #define OFX_ARCHSTR "Win32" | ||
| #endif | ||
| #define OFX_DIRSEP "\\" | ||
|
|
||
| #if defined(__MINGW32__) || defined(__MINGW64__) | ||
| #include <dirent.h> | ||
| #endif | ||
|
|
||
| #include "shlobj.h" | ||
| #include "tchar.h" | ||
| #endif | ||
|
|
||
| extern mlt_filter filter_openfx_init(mlt_profile profile, | ||
| mlt_service_type type, | ||
| const char *id, | ||
| char *arg); | ||
|
|
||
| static void plugin_mgr_destroy(mlt_properties p) | ||
| { | ||
| int cN = mlt_properties_count(mltofx_context); | ||
|
|
||
| for (int j = 0; j < cN; ++j) { | ||
| char *id = mlt_properties_get_name(mltofx_context, j); | ||
| mlt_properties pb = (mlt_properties) mlt_properties_get_data(mltofx_context, id, NULL); | ||
|
|
||
| char *dli = mlt_properties_get(pb, "dli"); | ||
| dli[0] = 'g'; | ||
| int index = mlt_properties_get_int(pb, "index"); | ||
|
|
||
| OfxGetPluginFn get_plugin = mlt_properties_get_data(mltofx_dl, dli, NULL); | ||
|
|
||
| if (get_plugin != NULL) { | ||
| OfxPlugin *pt = get_plugin(index); | ||
| if (pt == NULL) | ||
| continue; | ||
| pt->mainEntry(kOfxActionUnload, NULL, NULL, NULL); | ||
| } | ||
| } | ||
|
|
||
| int N = mlt_properties_get_int(p, "N"); | ||
|
|
||
| for (int i = 0; i < N; ++i) { | ||
| char tstr[12] = { | ||
| '\0', | ||
| }; | ||
| sprintf(tstr, "%d", i); | ||
| void *current_dlhandle = mlt_properties_get_data(mltofx_dl, tstr, NULL); | ||
| dlclose(current_dlhandle); | ||
| } | ||
| } | ||
|
|
||
| static mlt_properties metadata(mlt_service_type type, const char *id, void *data) | ||
| { | ||
| char file[PATH_MAX]; | ||
| snprintf(file, PATH_MAX, "%s/openfx/%s", mlt_environment("MLT_DATA"), (char *) data); | ||
| mlt_properties result = mlt_properties_parse_yaml(file); | ||
|
|
||
| mlt_properties pb = (mlt_properties) mlt_properties_get_data(mltofx_context, id, NULL); | ||
|
|
||
| char *dli = mlt_properties_get(pb, "dli"); | ||
| int index = mlt_properties_get_int(pb, "index"); | ||
|
|
||
| OfxGetPluginFn get_plugin = mlt_properties_get_data(mltofx_dl, dli, NULL); | ||
| OfxPlugin *pt = get_plugin(index); | ||
|
|
||
| dli[0] = 's'; | ||
| OfxSetHostFn set_host = mlt_properties_get_data(mltofx_dl, dli, NULL); | ||
| if (set_host != NULL) | ||
| set_host(&MltOfxHost); | ||
|
|
||
| mlt_properties_set(result, "identifier", id); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I run this command: Besides the noisy info message and crash, the metadata is ill-formed. It should be: The "Controls" item should not be there at all. And the identifier should be first and have a hyphen. See the schema in the framework. |
||
| mlt_properties_set(result, "title", id); | ||
|
|
||
| /* parameters */ | ||
| mlt_properties params = mlt_properties_new(); | ||
| mlt_properties_set_data(result, | ||
| "parameters", | ||
| params, | ||
| 0, | ||
| (mlt_destructor) mlt_properties_close, | ||
| NULL); | ||
|
|
||
| mltofx_fetch_params(pt, params, result); | ||
| return result; | ||
| } | ||
|
|
||
| MLT_REPOSITORY | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I run melt, i always see a new information message:
This message is printed even if I do not try to use any openfx filters. Is there a way to avoid the message?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plugins print their logs but I think this goes to the stderr so in bash we can forward it to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we want to turn off logging. Here is a patch that quiets the OCIO message:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I put a commit here which you are welcome to cherry-pick |
||
| { | ||
| MltOfxHost.host = (OfxPropertySetHandle) mlt_properties_new(); | ||
| mltofx_init_host_properties(MltOfxHost.host); | ||
|
|
||
| // Quiet warnings from plugins that use OCIO | ||
| char *ocio = getenv("OCIO"); | ||
| if (!ocio || !strcmp(ocio, "")) { | ||
| // If the OCIO environment variable is not set, set it to a built-in default config | ||
| setenv("OCIO", "ocio://ocio://default", 1); | ||
| } | ||
|
|
||
| char *dir; | ||
| char *openfx_path = getenv("OFX_PLUGIN_PATH"); | ||
| size_t archstr_len = strlen(OFX_ARCHSTR); | ||
|
|
||
| mltofx_context = mlt_properties_new(); | ||
| mltofx_dl = mlt_properties_new(); | ||
|
|
||
| if (openfx_path) { | ||
| int dli = 0; | ||
| char *saveptr; | ||
|
|
||
| for (char *strptr = openfx_path;; strptr = NULL) { | ||
| dir = strtok_r(strptr, MLT_DIRLIST_DELIMITER, &saveptr); | ||
| if (dir == NULL) | ||
| break; | ||
| size_t dir_len = strlen(dir); | ||
|
|
||
| DIR *d = opendir(dir); | ||
| if (!d) | ||
| continue; | ||
|
|
||
| struct dirent *de = readdir(d); | ||
| while (de) { | ||
| char *name = de->d_name; | ||
|
|
||
| char *bni = NULL; | ||
| if ((bni = strstr(name, ".ofx.bundle")) != NULL && bni[11] == '\0') { | ||
| char *barename = g_strndup(name, (int) (bni - name) + 4); | ||
| size_t name_len = (size_t) (bni - name) + 4 + 7; | ||
| /* 12b sizeof `Contents` word, 1 sizeof null byte */ | ||
| char *binpath = malloc(dir_len + name_len + 12 + (name_len - 7) + archstr_len | ||
| + 1); | ||
| sprintf(binpath, "%s/%s/Contents/%s/%s", dir, name, OFX_ARCHSTR, barename); | ||
|
|
||
| void *dlhandle = dlopen(binpath, RTLD_LOCAL | RTLD_LAZY); | ||
|
|
||
| ofx_set_host = dlsym(dlhandle, "OfxSetHost"); | ||
|
|
||
| ofx_get_plugin = dlsym(dlhandle, "OfxGetPlugin"); | ||
| ofx_get_number_of_plugins = dlsym(dlhandle, "OfxGetNumberOfPlugins"); | ||
| if (!ofx_get_plugin || !ofx_get_number_of_plugins) | ||
| goto parse_error; | ||
| NumberOfPlugins = ofx_get_number_of_plugins(); | ||
|
|
||
| char dl_n[16] = { | ||
| '\0', | ||
| }; | ||
| sprintf(dl_n, "%d", dli); | ||
|
|
||
| mlt_properties_set_data(mltofx_dl, dl_n, dlhandle, 0, NULL, NULL); | ||
| dl_n[0] = '\0'; | ||
| sprintf(dl_n, "gn%d", dli); | ||
| mlt_properties_set_data(mltofx_dl, | ||
| dl_n, | ||
| ofx_get_number_of_plugins, | ||
| 0, | ||
| (mlt_destructor) mlt_properties_close, | ||
| NULL); | ||
| dl_n[0] = '\0'; | ||
| sprintf(dl_n, "s%d", dli); | ||
| mlt_properties_set_data(mltofx_dl, | ||
| dl_n, | ||
| ofx_set_host, | ||
| 0, | ||
| (mlt_destructor) mlt_properties_close, | ||
| NULL); | ||
|
|
||
| dl_n[0] = '\0'; | ||
| sprintf(dl_n, "g%d", dli); | ||
| mlt_properties_set_data(mltofx_dl, | ||
| dl_n, | ||
| ofx_get_plugin, | ||
| 0, | ||
| (mlt_destructor) mlt_properties_close, | ||
| NULL); | ||
|
|
||
| dli++; | ||
|
|
||
| if (ofx_get_plugin == NULL) | ||
| goto parse_error; | ||
|
|
||
| for (int i = 0; i < NumberOfPlugins; ++i) { | ||
| OfxPlugin *plugin_ptr = ofx_get_plugin(i); | ||
| if (!plugin_ptr) | ||
| goto parse_error; | ||
|
|
||
| int detected = mltofx_detect_plugin(plugin_ptr); | ||
|
|
||
| if (!detected) | ||
| continue; | ||
|
|
||
| char *s = NULL; | ||
| size_t pluginIdentifier_len = strlen(plugin_ptr->pluginIdentifier); | ||
| s = malloc(pluginIdentifier_len + 8); | ||
| sprintf(s, "openfx.%s", plugin_ptr->pluginIdentifier); | ||
|
|
||
| // if colon `:` exists in plugin identifier | ||
| // change it to accent sign `^` because `:` | ||
| // can cause issues with mlt if put in filter | ||
| // name | ||
| char *str_ptr = strchr(s, ':'); | ||
| while (str_ptr != NULL) { | ||
| *str_ptr++ = '^'; | ||
| str_ptr = strchr(str_ptr, ':'); | ||
| } | ||
|
|
||
| mlt_properties p; | ||
| p = mlt_properties_new(); | ||
| mlt_properties_set_data(mltofx_context, | ||
| s, | ||
| p, | ||
| 0, | ||
| (mlt_destructor) mlt_properties_close, | ||
| NULL); | ||
|
|
||
| mlt_properties_set(p, "dli", dl_n); | ||
| mlt_properties_set_int(p, "index", i); | ||
|
|
||
| MLT_REGISTER(mlt_service_filter_type, s, filter_openfx_init); | ||
| MLT_REGISTER_METADATA(mlt_service_filter_type, | ||
| s, | ||
| metadata, | ||
| "filter_openfx.yml"); | ||
| free(s); | ||
| } | ||
|
|
||
| parse_error: | ||
|
|
||
| free(binpath); | ||
| free(barename); | ||
| } | ||
|
|
||
| de = readdir(d); | ||
| } | ||
|
|
||
| closedir(d); | ||
| } | ||
|
|
||
| mlt_properties_set_int(mltofx_dl, "N", dli); | ||
| mlt_factory_register_for_clean_up(mltofx_dl, (mlt_destructor) plugin_mgr_destroy); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I run melt and use an openfx filter, melt always ends with a crash. Here is the gdb backtrace:
Do you also experience this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sometimes I face similar issues with the git version of melt and not only
openfxbranch but using kdenlive does not cause this issue. I need to do more testing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seem to be a handful of plugins that crash when we call
From inspection, I notice that we load and then unload all plugins while we are discovering them. Then, we load them all again when we are generating metadata - and we leave them all loaded until the program closes and we call plugin_mgr_destroy. Do you know if it is good to leave them all loaded? Does that consume extra resources? Should we try to only keep open plugins that we are using?