Add PipeWire camera feeds#109500
Conversation
d10a7ef to
5c686c2
Compare
5c686c2 to
9d411d7
Compare
I think I can give a hand :D What issues are you having exactly? |
fee04a9 to
ab1cbaf
Compare
I tried to generate sowrap from But there are lots of parse errors, mostly coming from SPA headers like:
|
ab1cbaf to
80403e9
Compare
|
Hi, I investigated the issue and I think I found a solution :D We parse C code through pycparser, which by design does not support compiler extensions like In addition to that, the fake libc is missing the definition of I addressed those issues in a very rough patch to dynload-wrapper which you can try below. I haven't tried building the files but at a glance they seem correct. Note that, according to I did this invocation: ../dynload-wrapper/generate-wrapper.py \
--include-dir ./thirdparty/linuxbsd_headers/pipewire/src/ \
--include-dir ./thirdparty/linuxbsd_headers/pipewire/spa/include/ \
--include ./thirdparty/linuxbsd_headers/pipewire/src/pipewire/pipewire.h \
--soname libpipewire-0.3.so.0 \
--init-name pipewire \
--sys-include '<pipewire/pipewire.h>' \
--output-header ./platform/linuxbsd/pipewire-so_wrap.h \
--output-implementation ./platform/linuxbsd/pipewire-so_wrap.cWith this dynload-wrapper patch: diff --git a/fake_libc_include/_fake_typedefs.h b/fake_libc_include/_fake_typedefs.h
index 3442dc1..031f33f 100644
--- a/fake_libc_include/_fake_typedefs.h
+++ b/fake_libc_include/_fake_typedefs.h
@@ -176,4 +176,6 @@ typedef struct xcb_connection_t xcb_connection_t;
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;
+typedef struct locale_t locale_t;
+
#endif
diff --git a/generate-wrapper.py b/generate-wrapper.py
index 62b6294..a122823 100755
--- a/generate-wrapper.py
+++ b/generate-wrapper.py
@@ -29,6 +29,7 @@ import textwrap
from datetime import datetime
try:
+ import pycparser
from pycparser import c_parser, c_ast, parse_file, c_generator
from pycparser.c_ast import Decl, FuncDecl, PtrDecl
except:
@@ -36,6 +37,14 @@ except:
print("Try installing it with pip install pycparser or using your distributions package manager.")
sys.exit(1)
+try:
+ import pycparserext
+ from pycparserext import ext_c_parser, ext_c_generator
+ from pycparserext.ext_c_parser import FuncDeclExt
+except:
+ print("pycparserext not found.")
+ sys.exit(1)
+
VERSION="0.7"
URL="https://github.com/hpvb/dynload-wrapper"
NOW=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -43,7 +52,8 @@ PROGNAME=os.path.basename(sys.argv[0])
FLAGS=""
def stringify_declaration(t):
- generator = c_generator.CGenerator()
+ #generator = c_generator.CGenerator()
+ generator = ext_c_generator.GnuCGenerator()
return generator.visit(t)
def get_name(t):
@@ -73,14 +83,17 @@ def parse_header(filename, omit_prefix, initname, ignore_headers = [], ignore_al
cpp_args.append(include_dir)
print(f"cpp_args: {cpp_args}")
- ast = parse_file(filename, use_cpp=True, cpp_path='gcc', cpp_args=cpp_args)
+ text = pycparser.preprocess_file(filename, cpp_path='gcc', cpp_args=cpp_args)
+ #parser = c_parser.CParser()
+ parser = ext_c_parser.GnuCParser()
+ ast = parser.parse(text)
functions = []
sym_definitions = []
for ext in ast.ext:
if isinstance(ext, Decl):
- if not isinstance(ext.type, FuncDecl):
+ if not isinstance(ext.type, FuncDeclExt):
continue
skip = FalseAgain please excuse the crudity of this model. I didn't have time to Lastly, for some reason I get some debug HTH :D CC @hpvb (I'll make a PR soon™! Cleaned up of course) |
I managed to generate sowrap for pipewire with You saved my day and this PR, thank you very much! |
8ec544a to
682ba2f
Compare
7833779 to
84308e4
Compare
84308e4 to
fd748ed
Compare
|
Please let me know if the commits need to be squashed. |
|
Please do squash them, we require single commits |
28465b4 to
f7ee552
Compare
|
f7ee552f8908b1875db917097222d13ad5815374 removed unused proxy callback. |
f7ee552 to
709797e
Compare
709797e to
d6018bd
Compare
c70673c to
dbd6ab8
Compare
|
CI now reports |
|
@j20001970 diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp
index f598fa4226..aaeac49cd9 100644
--- a/modules/camera/register_types.cpp
+++ b/modules/camera/register_types.cpp
@@ -60,8 +60,15 @@ void initialize_camera_module(ModuleInitializationLevel p_level) {
int dylibloader_verbose = 0;
#endif // defined(DEBUG_ENABLED)
if (initialize_pipewire(dylibloader_verbose) == 0) {
- print_verbose("CameraServer: Using PipeWire driver.");
- CameraServer::make_default<CameraPipeWire>();
+ // pw_check_library_version is available since 0.3.75.
+ // If the function is not available or version is too old, fall back to V4L2.
+ if (pw_check_library_version_dylibloader_wrapper_pipewire && pw_check_library_version(PW_MAJOR, PW_MINOR, PW_MICRO)) {
+ print_verbose("CameraServer: Using PipeWire driver.");
+ CameraServer::make_default<CameraPipeWire>();
+ } else {
+ print_verbose(vformat("CameraServer: PipeWire version too old (%s), falling back to V4L2 driver.", pw_get_library_version()));
+ CameraServer::make_default<CameraLinux>();
+ }
} else {
print_verbose("CameraServer: Using V4L2 driver.");
CameraServer::make_default<CameraLinux>(); |
|
5c2a132aadc09a2a2901ec149b0ec402f2855564 added MJPEG format support. Please note that MJPEG format might not work as expected at the moment, since the stream from webcams might contain extraneous bytes and jpeg_turbo_load_image_from_buffer consider such warning as error (this might be fixed by #113359). And some of the code has changed since last approval, should I re-request the review? |
|
e633f2d1453dc1a7fe0d20560c86d93beab01bfd fixed EDIT: Accidentely changed timeout in |
|
The PR currently has a bug that the camera feeds will fail to start streaming on systems using PipeWire 1.6.1 (maybe 1.6.0) onward. The stream from PipeWire side will fail with error message like Strangely, PipeWire tutorial 5 from official documentation also seems stopped working (the program does not report captured frame byte size), while some webcam capture applications using PipeWire like OBS still work as expected. So it is likely that there are still something the PR does not handle well. Please do not merge this until the issue is solved. |
d7c64a8 have fixed aforementioned issue by specifying buffer datatype when connecting the stream. The PR should now work on newer PipeWire version. on_stream_state_changed callback is also added to notify stream error. Now to respond the review feedback from @Calinou (thanks for the review!):
When CameraPipeWire::set_monitoring_feeds is set to false, all feeds created by
I can't seem to reproduce the problem, does that mean exiting app need to happen after a new format is selected, as well as before the feed start providing frames with the new format?
I'm not sure if Windows could provide webcam resolution higher than the specs. I took a look at the Elgato website, it states the video resolution up to |




This PR uses PipeWire to provide camera feeds on Linux systems.
The benefits of using PipeWire for camera devices includes not having to use V4L2 kernel API directly, better integrated for desktop environments (camera indicator on KDE Plasma for example), and sandboxed camera access is also possible by using XDG desktop portal.
Camera feed driver on linuxbsd will be selected at runtime, and fallback to V4L2 driver if failed to initialize PipeWire.
TODO:
monitoring_feedsto true (supersede SupportOS::request_permission("CAMERA")on linuxbsd using XDG Desktop Portal #100396)Tested with the following shader:
Tested with GDMP demo vision tasks without enabling camera feed addon.
Tested with godot-camerafeed-demo.