-
-
Notifications
You must be signed in to change notification settings - Fork 21.9k
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
Added webcam support for Linux #47967
Conversation
afdafc8
to
b71add4
Compare
// get some info | ||
name = device->name; | ||
// I do not think that another position is possible on linux | ||
position = CameraFeed::FEED_UNSPECIFIED; |
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.
Unspecified I think is fine for a webcam, front/back really only applies to phones.
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.
I'm not a linux guy so I can't really test whether this works as advertised but doing a quick code review it looked sensible.
Would like someone to look at this who knows more about linux, @hpvb maybe you can have a quick look?
do { | ||
r = funcs->ioctl(fd, request, arg); | ||
} while (-1 == r && (EINTR == errno || errno == EAGAIN)); | ||
return r; |
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.
yoda coding! love it but not really our style :)
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.
TBH that was just how the example was implemented. I found a little weird too, but hey semantics are the same.^^ I can change this and make it more common if needed.
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.
I'll let @akien-mga be the judge of coding styles :)
I do think Yoda coding has merit, it does catch certain errors, but I don't think we've got it anywhere else in the source code.
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.
Indeed, we don't use Yoda conditions in Godot's codebase as far as I know.
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.
So I removed the Yoda conditions to not confuse the codebase.
Ah as I want to mention. I would also like to push it to the godot 3.x branch, but therefore the Vector<uint8_t> must be changed to PoolVector<uint8_t>. But i guess it should be cherrypicked after this one is merged? |
Yes that would be a cherry pick :) |
…e hotplug functionality.
b71add4
to
c7411cc
Compare
Just gonna link the webcam support issue here. Should make it easier for me to adjust the issue when this gets merged: #46531 |
- Doesn't compile; see godotengine#47967
Does this code support setting the scene's Code source: I merged this code into our Godot 3.2 fork here:
Using this to run godot with a webcam located at
set results in
but just results in a black ground; moreover, the webcam doesn't even turn on. Tracing the source of the issue: I've discovered that the specific failure is located in RasterizerSceneGLES3::render_scene, where if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) {
// copy our camera feed to our background
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// ... |
After some fidgeting I got this to work, but only from gdb: https://www.youtube.com/watch?v=KhTs9uriXDQ bool CameraFeedX11::activate_feed() {
// activate streaming if not already
if (!device->streaming) {
if (!device->check_device()) {
return false;
}
if (!device->request_buffers()) {
device->close();
return false;
}
if (!device->start_streaming(this)) {
device->cleanup_buffers();
device->close();
return false;
}
};
return true;
}; If I manually step through this via gdb ( |
Does it work if you call |
Yes, changing the function to the following makes now it work without having to manually step through it w/GDB: bool CameraFeedX11::activate_feed() {
// activate streaming if not already
if (!device->streaming) {
OS::get_singleton()->delay_usec(100); //<-- here
if (!device->check_device()) {
return false;
}
OS::get_singleton()->delay_usec(100); //<-- here
if (!device->request_buffers()) {
device->close();
return false;
}
OS::get_singleton()->delay_usec(100); //<-- here
if (!device->start_streaming(this)) {
device->cleanup_buffers();
device->close();
return false;
}
};
return true;
}; |
fd = funcs->open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0);
|
The webcam image is also left-right inverted when shown in the Environment, which is fixed by a call to |
Hey all - excited to see this. I'm trying to reproduce with a build from the fork. I get both a usb web cam and CV1 external cameras detected with libv4l2 in the log and can get them via |
Will this work with a v4l2loopback-device? (eg Screencapture/OBS) |
I don't think this should be done in the module, because sometimes it depends on the webcam what kind of picture it sends. In my opinion such things should be done in the shader.
To solve this async issue I guess your proposal with the little delay is best. What do the others think. I do not think that making the open call blocking is a good idea
Yes it works also with a v4l2loopback device (I tested this) |
I'm still missing something in terms of how to get a basic test scene running. It seems like CameraServer should be returning feeds as CameraX11 objects, but invoking functions on the returned object yields a 'non-existent function' error. Any suggestions for setup or scene links? Also, should
|
Indeed, |
Updating the
I'm a little out of my depth on the c++ front so making some guesses - is something like the above required to invoke inherited class functions from gdscript in v4? |
well, this explains a lot: https://github.com/godotengine/godot/blob/master/servers/camera/camera_feed.cpp#L36-L37 (turns out manually binding the methods in |
From what I can piece together, the circumvented
Is there a thread of work covering this or would it just be an isolated PR? |
This comment has been minimized.
This comment has been minimized.
PR for CameraFeed fix - #51581 |
Confirmed to work via the lib4vl2 method on linux in-editor (thx for the demo scene in the PR) - but the texture doesn't render in a played scene, even with a script to cycle through and |
It seems to work only 3D scene is opened, closed and reopened in editor, or if it's assigned to 2D sprite (in this case it's working in running project, but only after resizing the window). Probably something in the CameraTerxture/Feed/Server is initialized before RenderingServer is ready, but I'm not sure what's exactly wrong. |
I was also implementing linux camera support, so maybe we could combine best of both solutions? |
What testing is needed for this to be merged? What is required for this to be backported to 3.x? |
See my note above:
And according to this you also have to change from: uint8_t *w = img_data.ptrw();
// TODO: Buffer is 1024 Byte longer?
memcpy(w, buffer, width * height * 3); to: PoolVector<uint8_t>::Write w = img_data.write();
// TODO: Buffer is 1024 Byte longer?
memcpy(w.ptr(), buffer, width*height*3); This should be enough to backport it to godot 3.x |
Will this be merged into 3.5? |
This needs to be merged in Note that there is another pull request implementing the same feature: #53666 If you want to help get this merged, you can test it locally on your own device and make sure it works as expected 🙂 |
Superseded by #53666. Thanks for the contribution nonetheless! |
I added webcam support for Linux.
I used libv4l2 which is dynamically loaded if present. If it is not present the kernel default v4l2 library is used.
It should be able to grab images even without libv4l2 if the camera supports RGB output directly.
With libv4l2 the image is always grabbed as RGB8 image.
I also implemented a simple hotplug feature which just checks the /dev/video* files every second.
I tested it with the TestCameraServer Project from https://github.com/BastiaanOlij/godot3_test_projects.git
I could only test for TYPE_IO_MMAP as my camera only supports this, but I implemented also the other types using the information provided by https://kernel.readthedocs.io/en/latest/media/uapi/v4l/capture.c.html