Skip to content

Implement "Keep Last Received Frame/Timeout" functionality#1330

Merged
Trouffman merged 11 commits into
DistroAV:masterfrom
Lordmau5:feat/keep-last-received-frame
Aug 17, 2025
Merged

Implement "Keep Last Received Frame/Timeout" functionality#1330
Trouffman merged 11 commits into
DistroAV:masterfrom
Lordmau5:feat/keep-last-received-frame

Conversation

@Lordmau5

@Lordmau5 Lordmau5 commented Aug 4, 2025

Copy link
Copy Markdown
Contributor

This is a new checkbox that is enabled by default. When it is enabled it will keep the last frame that was received on the source, no matter if the sender NDI instance was disconnected or is sending "none" frame data. When it is disabled, it will wait for up to 3 seconds to receive a new frame and, if there is no new frame, will clear it on the receiver end.

The way this is possible is via. a new helper method called is_filter_invalid (probably not the final name) which is checking the source width and height, as well as if the filter is enabled on the source and if the source is active anywhere. Sources don't update when they aren't rendered in the main OBS view from what I can tell (e.g. a Browser Source would just seem like it's frozen) so this is in-line with the current way OBS handles it.

This PR supersedes #1276 by for example making sure the NDI connection stays alive instead of destroying it the moment the source / filter gets invalid.

This is a new checkbox that is enabled by default. When it is enabled it will keep the last frame that was received on the source, no matter if the sender NDI instance was disconnected or is sending "none" frame data.
When it is disabled, it will wait for up to 3 seconds to receive a new frame and, if there is no new frame, will clear it on the receiver end.

The way this is possible is via. a new helper method called `is_filter_invalid` (probably not the final name) which is checking the source width and height, as well as if the filter is enabled on the source and if the source is active anywhere.
Sources don't update when they aren't rendered in the main OBS view from what I can tell (e.g. a Browser Source would just seem like it's frozen) so this is in-line with the current way OBS handles it
Comment thread src/ndi-filter.cpp Outdated
Comment thread src/ndi-filter.cpp Outdated
@Lordmau5

Lordmau5 commented Aug 6, 2025

Copy link
Copy Markdown
Contributor Author

Okay I've renamed is_filter_invalid to is_filter_valid with inverted logic.

Additionally, I thought a bit more about the ndi_sender_create method and its naming and I think it is better that we just name it that and make sure it destroys the sender during it.
It's only really called with ndi_filter_update (when the filter updates) and in ndi_filter_tick (during video ticks, and only if f->ndi_sender is a nullptr)

@BitRate27

Copy link
Copy Markdown
Contributor

In addition to allowing a NDI source to go black if no NDI data is received after 3 seconds, this PR also allows a second instance of OBS receiving Dedicated NDI Output from another OBS to also go black when no data is being sent.

Prerequisites:

Two portable OBSs (OBS 1 and OBS 2) running
Test Pattern App from NDI Tools running

  1. Open OBS 1
  2. Add a new NDI Source using
  3. Select Test Pattern as NDI source
  4. Uncheck "Keep the last frame received"
  5. Add Dedicated NDI Output filter to NDI Source
  6. Open OBS 2
  7. Add a NDI Source
  8. Select Dedicated NDI Output as NDI source
  9. Uncheck "Keep the last frame received"
  10. Shutdown Test Pattern App
  • Test Pattern disappears in OBS 1 in 3 seconds
  • Dedicated NDI Output disappears in OBS 2 in 6 seconds

Observations:
OBS is responding correctly to the Test Pattern NDI Source terminating.
OBS is responding correctly to a Dedicated NDI Output sending an empty frame (due to invalid frame on NDI source hosting filter)
Dedicated NDI Output still exists after filter disabled or source no longer sending (just nothing being sent)

@Trouffman Trouffman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While reviewing this change, the naming triggered me multiple time (especially as we use this "last frame" codename for the "behavior".

After some thought I suggest the following :

  • Behavior is a "Connection Behavior"

Also having only a tick box is lacking context and might lead to confusion in the same manner we had when developing the "behavior" feature.

Suggestion :

"On timeout"

  • Keep last received content (frame)
  • Clear/reset the source (3sec)

PoC :
image

@Lordmau5

Copy link
Copy Markdown
Contributor Author

While reviewing this change, the naming triggered me multiple time (especially as we use this "last frame" codename for the "behavior".

After some thought I suggest the following :

* Behavior is a "Connection Behavior"

Also having only a tick box is lacking context and might lead to confusion in the same manner we had when developing the "behavior" feature.

Suggestion :

"On timeout"

* Keep last received content (frame)

* Clear/reset the source (3sec)

PoC : image

Much better than the checkbox, I agree - I'm not good with UI/UX and while it made sense in my head I can fully see it causing confusion for other users

@Trouffman

Copy link
Copy Markdown
Collaborator

This should be feature-complete. Translation added in all language using machine learning except for : English, French, Spanish

@Trouffman Trouffman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked the tickbox to be a drop-down for better clarity.

@Trouffman Trouffman changed the title Implement "Keep Last Received Frame" functionality Implement "Keep Last Received Frame/Timeout" functionality Aug 17, 2025
@Trouffman
Trouffman merged commit 5c56d91 into DistroAV:master Aug 17, 2025
6 checks passed
@Lordmau5
Lordmau5 deleted the feat/keep-last-received-frame branch August 17, 2025 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants