@@ -188,17 +188,21 @@ void CameraFeed::set_rgb_image(const Ref<Image> &p_rgb_img) {
188188 int new_width = p_rgb_img->get_width ();
189189 int new_height = p_rgb_img->get_height ();
190190
191+ // Emit `format_changed` signal if feed datatype or frame size is changed.
192+ // The signal is deferred to ensure:
193+ // - They are emitted on Godot's main thread.
194+ // - Both datatype and frame size are updated before the emission.
195+ if (datatype != CameraFeed::FEED_RGB || (base_width != new_width) || (base_height != new_height)) {
196+ call_deferred (" emit_signal" , format_changed_signal_name);
197+ }
198+
191199 if ((base_width != new_width) || (base_height != new_height)) {
192200 // We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
193201 base_width = new_width;
194202 base_height = new_height;
195203
196204 RID new_texture = RenderingServer::get_singleton ()->texture_2d_create (p_rgb_img);
197205 RenderingServer::get_singleton ()->texture_replace (texture[CameraServer::FEED_RGBA_IMAGE], new_texture);
198-
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);
202206 } else {
203207 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_RGBA_IMAGE], p_rgb_img);
204208 }
@@ -216,17 +220,21 @@ void CameraFeed::set_ycbcr_image(const Ref<Image> &p_ycbcr_img) {
216220 int new_width = p_ycbcr_img->get_width ();
217221 int new_height = p_ycbcr_img->get_height ();
218222
223+ // Emit `format_changed` signal if feed datatype or frame size is changed.
224+ // The signal is deferred to ensure:
225+ // - They are emitted on Godot's main thread.
226+ // - Both datatype and frame size are updated before the emission.
227+ if (datatype != CameraFeed::FEED_YCBCR || (base_width != new_width) || (base_height != new_height)) {
228+ call_deferred (" emit_signal" , format_changed_signal_name);
229+ }
230+
219231 if ((base_width != new_width) || (base_height != new_height)) {
220232 // We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
221233 base_width = new_width;
222234 base_height = new_height;
223235
224236 RID new_texture = RenderingServer::get_singleton ()->texture_2d_create (p_ycbcr_img);
225237 RenderingServer::get_singleton ()->texture_replace (texture[CameraServer::FEED_RGBA_IMAGE], new_texture);
226-
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);
230238 } else {
231239 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_RGBA_IMAGE], p_ycbcr_img);
232240 }
@@ -249,6 +257,14 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
249257 int new_y_width = p_y_img->get_width ();
250258 int new_y_height = p_y_img->get_height ();
251259
260+ // Emit `format_changed` signal if feed datatype or frame size is changed.
261+ // The signal is deferred to ensure:
262+ // - They are emitted on Godot's main thread.
263+ // - Both datatype and frame size are updated before the emission.
264+ if (datatype != CameraFeed::FEED_YCBCR_SEP || (base_width != new_y_width) || (base_height != new_y_height)) {
265+ call_deferred (" emit_signal" , format_changed_signal_name);
266+ }
267+
252268 if ((base_width != new_y_width) || (base_height != new_y_height)) {
253269 // We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
254270 base_width = new_y_width;
@@ -261,10 +277,6 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
261277 RID new_texture = RenderingServer::get_singleton ()->texture_2d_create (p_cbcr_img);
262278 RenderingServer::get_singleton ()->texture_replace (texture[CameraServer::FEED_CBCR_IMAGE], new_texture);
263279 }
264-
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);
268280 } else {
269281 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_Y_IMAGE], p_y_img);
270282 RenderingServer::get_singleton ()->texture_2d_update (texture[CameraServer::FEED_CBCR_IMAGE], p_cbcr_img);
@@ -278,6 +290,14 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
278290}
279291
280292void CameraFeed::set_external (int p_width, int p_height) {
293+ // Emit `format_changed` signal if feed datatype or frame size is changed.
294+ // The signal is deferred to ensure:
295+ // - They are emitted on Godot's main thread.
296+ // - Both datatype and frame size are updated before the emission.
297+ if (datatype != CameraFeed::FEED_EXTERNAL || (base_width != p_width) || (base_height != p_height)) {
298+ call_deferred (" emit_signal" , format_changed_signal_name);
299+ }
300+
281301 if ((base_width != p_width) || (base_height != p_height)) {
282302 // We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
283303 base_width = p_width;
0 commit comments