diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml index f30edb1d361..c9a423efe62 100644 --- a/doc/classes/CameraServer.xml +++ b/doc/classes/CameraServer.xml @@ -45,6 +45,12 @@ + + + If [code]true[/code], the server is actively monitoring available camera feeds. + This has a performance cost, so only set it to [code]true[/code] when you're actively accessing the camera. + + diff --git a/modules/camera/camera_linux.cpp b/modules/camera/camera_linux.cpp index a1b0b5b49e5..c95069442e0 100644 --- a/modules/camera/camera_linux.cpp +++ b/modules/camera/camera_linux.cpp @@ -162,11 +162,25 @@ bool CameraLinux::_can_query_format(int p_file_descriptor, int p_type) { return ioctl(p_file_descriptor, VIDIOC_G_FMT, &format) != -1; } -CameraLinux::CameraLinux() { - camera_thread.start(CameraLinux::camera_thread_func, this); +inline void CameraLinux::set_monitoring_feeds(bool p_monitoring_feeds) { + if (p_monitoring_feeds == monitoring_feeds) { + return; + } + + CameraServer::set_monitoring_feeds(p_monitoring_feeds); + if (p_monitoring_feeds) { + camera_thread.start(CameraLinux::camera_thread_func, this); + } else { + exit_flag.set(); + if (camera_thread.is_started()) { + camera_thread.wait_to_finish(); + } + } } CameraLinux::~CameraLinux() { exit_flag.set(); - camera_thread.wait_to_finish(); + if (camera_thread.is_started()) { + camera_thread.wait_to_finish(); + } } diff --git a/modules/camera/camera_linux.h b/modules/camera/camera_linux.h index 4b362eb5d80..10710943900 100644 --- a/modules/camera/camera_linux.h +++ b/modules/camera/camera_linux.h @@ -52,6 +52,8 @@ private: bool _can_query_format(int p_file_descriptor, int p_type); public: - CameraLinux(); + CameraLinux() = default; ~CameraLinux(); + + void set_monitoring_feeds(bool p_monitoring_feeds) override; }; diff --git a/modules/camera/camera_macos.h b/modules/camera/camera_macos.h index ba9723a99b8..1b0ad294e6b 100644 --- a/modules/camera/camera_macos.h +++ b/modules/camera/camera_macos.h @@ -37,7 +37,8 @@ class CameraMacOS : public CameraServer { public: - CameraMacOS(); + CameraMacOS() = default; void update_feeds(); + void set_monitoring_feeds(bool p_monitoring_feeds) override; }; diff --git a/modules/camera/camera_macos.mm b/modules/camera/camera_macos.mm index 3d0e08045bf..87e3d397b0b 100644 --- a/modules/camera/camera_macos.mm +++ b/modules/camera/camera_macos.mm @@ -359,10 +359,20 @@ void CameraMacOS::update_feeds() { }; } -CameraMacOS::CameraMacOS() { - // Find available cameras we have at this time - update_feeds(); +void CameraMacOS::set_monitoring_feeds(bool p_monitoring_feeds) { + if (p_monitoring_feeds == monitoring_feeds) { + return; + } - // should only have one of these.... - device_notifications = [[MyDeviceNotifications alloc] initForServer:this]; + CameraServer::set_monitoring_feeds(p_monitoring_feeds); + if (p_monitoring_feeds) { + // Find available cameras we have at this time. + update_feeds(); + + // Get notified on feed changes. + device_notifications = [[MyDeviceNotifications alloc] initForServer:this]; + } else { + // Stop monitoring feed changes. + device_notifications = nil; + } } diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp index b78a0c44e75..3d01399a84e 100644 --- a/servers/camera_server.cpp +++ b/servers/camera_server.cpp @@ -39,6 +39,10 @@ CameraServer::CreateFunc CameraServer::create_func = nullptr; void CameraServer::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_monitoring_feeds", "is_monitoring_feeds"), &CameraServer::set_monitoring_feeds); + ClassDB::bind_method(D_METHOD("is_monitoring_feeds"), &CameraServer::is_monitoring_feeds); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring_feeds"), "set_monitoring_feeds", "is_monitoring_feeds"); + ClassDB::bind_method(D_METHOD("get_feed", "index"), &CameraServer::get_feed); ClassDB::bind_method(D_METHOD("get_feed_count"), &CameraServer::get_feed_count); ClassDB::bind_method(D_METHOD("feeds"), &CameraServer::get_feeds); @@ -61,6 +65,10 @@ CameraServer *CameraServer::get_singleton() { return singleton; } +void CameraServer::set_monitoring_feeds(bool p_monitoring_feeds) { + monitoring_feeds = p_monitoring_feeds; +} + int CameraServer::get_free_id() { bool id_exists = true; int newid = 0; @@ -80,6 +88,8 @@ int CameraServer::get_free_id() { } int CameraServer::get_feed_index(int p_id) { + ERR_FAIL_COND_V_MSG(!monitoring_feeds, -1, "CameraServer is not actively monitoring feeds; call set_monitoring_feeds(true) first."); + for (int i = 0; i < feeds.size(); i++) { if (feeds[i]->get_id() == p_id) { return i; @@ -90,6 +100,8 @@ int CameraServer::get_feed_index(int p_id) { } Ref CameraServer::get_feed_by_id(int p_id) { + ERR_FAIL_COND_V_MSG(!monitoring_feeds, nullptr, "CameraServer is not actively monitoring feeds; call set_monitoring_feeds(true) first."); + int index = get_feed_index(p_id); if (index == -1) { @@ -129,16 +141,19 @@ void CameraServer::remove_feed(const Ref &p_feed) { } Ref CameraServer::get_feed(int p_index) { + ERR_FAIL_COND_V_MSG(!monitoring_feeds, nullptr, "CameraServer is not actively monitoring feeds; call set_monitoring_feeds(true) first."); ERR_FAIL_INDEX_V(p_index, feeds.size(), nullptr); return feeds[p_index]; } int CameraServer::get_feed_count() { + ERR_FAIL_COND_V_MSG(!monitoring_feeds, 0, "CameraServer is not actively monitoring feeds; call set_monitoring_feeds(true) first."); return feeds.size(); } TypedArray CameraServer::get_feeds() { + ERR_FAIL_COND_V_MSG(!monitoring_feeds, {}, "CameraServer is not actively monitoring feeds; call set_monitoring_feeds(true) first."); TypedArray return_feeds; int cc = get_feed_count(); return_feeds.resize(cc); @@ -151,6 +166,7 @@ TypedArray CameraServer::get_feeds() { } RID CameraServer::feed_texture(int p_id, CameraServer::FeedImage p_texture) { + ERR_FAIL_COND_V_MSG(!monitoring_feeds, RID(), "CameraServer is not actively monitoring feeds; call set_monitoring_feeds(true) first."); int index = get_feed_index(p_id); ERR_FAIL_COND_V(index == -1, RID()); diff --git a/servers/camera_server.h b/servers/camera_server.h index 406d7b6aadb..bb34229dade 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -64,6 +64,7 @@ private: protected: static CreateFunc create_func; + bool monitoring_feeds = false; Vector> feeds; static CameraServer *singleton; @@ -88,6 +89,9 @@ public: return server; } + virtual void set_monitoring_feeds(bool p_monitoring_feeds); + _FORCE_INLINE_ bool is_monitoring_feeds() const { return monitoring_feeds; } + // Right now we identify our feed by it's ID when it's used in the background. // May see if we can change this to purely relying on CameraFeed objects or by name. int get_free_id();