@@ -196,13 +196,17 @@ void CameraFeed::set_rgb_image(const Ref<Image> &p_rgb_img) {
196196 RID new_texture = RenderingServer::get_singleton ()->texture_2d_create (p_rgb_img);
197197 RenderingServer::get_singleton ()->texture_replace (texture[CameraServer::FEED_RGBA_IMAGE], new_texture);
198198
199- emit_signal (format_changed_signal_name);
199+ // Defer `format_changed` signals to ensure they are emitted on Godot's main thread.
200+ // This also makes sure the datatype of the feed is updated before the emission.
201+ call_deferred (" emit_signal" , format_changed_signal_name);
200202 } else {
201203 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_RGBA_IMAGE], p_rgb_img);
202204 }
203205
204206 datatype = CameraFeed::FEED_RGB;
205- emit_signal (frame_changed_signal_name);
207+ // Most of the time the pixel data of camera devices comes from threads outside Godot.
208+ // Defer `frame_changed` signals to ensure they are emitted on Godot's main thread.
209+ call_deferred (" emit_signal" , frame_changed_signal_name);
206210 }
207211}
208212
@@ -220,13 +224,17 @@ void CameraFeed::set_ycbcr_image(const Ref<Image> &p_ycbcr_img) {
220224 RID new_texture = RenderingServer::get_singleton ()->texture_2d_create (p_ycbcr_img);
221225 RenderingServer::get_singleton ()->texture_replace (texture[CameraServer::FEED_RGBA_IMAGE], new_texture);
222226
223- emit_signal (format_changed_signal_name);
227+ // Defer `format_changed` signals to ensure they are emitted on Godot's main thread.
228+ // This also makes sure the datatype of the feed is updated before the emission.
229+ call_deferred (" emit_signal" , format_changed_signal_name);
224230 } else {
225231 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_RGBA_IMAGE], p_ycbcr_img);
226232 }
227233
228234 datatype = CameraFeed::FEED_YCBCR;
229- emit_signal (frame_changed_signal_name);
235+ // Most of the time the pixel data of camera devices comes from threads outside Godot.
236+ // Defer `frame_changed` signals to ensure they are emitted on Godot's main thread.
237+ call_deferred (" emit_signal" , frame_changed_signal_name);
230238 }
231239}
232240
@@ -254,14 +262,18 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
254262 RenderingServer::get_singleton ()->texture_replace (texture[CameraServer::FEED_CBCR_IMAGE], new_texture);
255263 }
256264
257- emit_signal (format_changed_signal_name);
265+ // Defer `format_changed` signals to ensure they are emitted on Godot's main thread.
266+ // This also makes sure the datatype of the feed is updated before the emission.
267+ call_deferred (" emit_signal" , format_changed_signal_name);
258268 } else {
259269 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_Y_IMAGE], p_y_img);
260270 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_CBCR_IMAGE], p_cbcr_img);
261271 }
262272
263273 datatype = CameraFeed::FEED_YCBCR_SEP;
264- emit_signal (frame_changed_signal_name);
274+ // Most of the time the pixel data of camera devices comes from threads outside Godot.
275+ // Defer `frame_changed` signals to ensure they are emitted on Godot's main thread.
276+ call_deferred (" emit_signal" , frame_changed_signal_name);
265277 }
266278}
267279
@@ -276,7 +288,9 @@ void CameraFeed::set_external(int p_width, int p_height) {
276288 }
277289
278290 datatype = CameraFeed::FEED_EXTERNAL;
279- emit_signal (frame_changed_signal_name);
291+ // Most of the time the pixel data of camera devices comes from threads outside Godot.
292+ // Defer `frame_changed` signals to ensure they are emitted on Godot's main thread.
293+ call_deferred (" emit_signal" , frame_changed_signal_name);
280294}
281295
282296bool CameraFeed::activate_feed () {
0 commit comments