Skip to content
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

[RSDK-6469] Set x264 bitrate based on resolution and fps #4769

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

seanavery
Copy link
Member

@seanavery seanavery commented Feb 3, 2025

Description

This PR gives a more accurate bitrate estimation to our libx264 pipeline based on resolution and framerate. The idea here is that smaller streams will use less bandwidth and we will get better quality out of larger streams.

  • Removes hardcoded 3.2 Mbps bitrate.
  • Adds look up for framerate from Properties and if it is not found default to 30.
  • Calculates bitrate using a reasonable 0.15 bits per pixel ratio.
  • Adds minimum bitrate to avoid buffering issues with small frame sizes.
  • Adds a maximum bitrate that is safely over 20fps 4k stream size.

Examples bitrates:

640p at 30 fps: 640*480*30*0.15 - > 1.382400 Mbps
1080p at 30fps : 1920*1080*30*0.15 -> 9.331200 Mbps
4k at 20fps: 3840*2160*20*0.15 -> 24.883200 Mbps

Tests

  • webcam
    • picks up framerate from properties ✅
    • suitable quality across multiple resolutiosn ✅
  • viamrtsp
    • suitable quality at 4k resolutions ✅
  • dyanmic resolution
    • suitable quality at extremely small frame sizes ✅

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 3, 2025
@@ -622,6 +622,11 @@ func (c *webcam) Properties(ctx context.Context) (camera.Properties, error) {
if err != nil {
return camera.Properties{}, err
}

if c.conf.FrameRate > 0 {
props.FrameRate = c.conf.FrameRate
Copy link
Member Author

@seanavery seanavery Feb 3, 2025

Choose a reason for hiding this comment

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

Moved framerate props setter outside of conditional IntrinsicParams == nil block.
!!! Need to rebase here with latest webcam for same fix. Fixed in latest. ✅

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 3, 2025
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 3, 2025
@seanavery seanavery requested review from hexbabe and randhid February 3, 2025 18:54
// calcBitrateFromResolution calculates the bitrate based on the given resolution and framerate.
func calcBitrateFromResolution(width, height int, framerate float32) int {
bitrate := int(float32(width) * float32(height) * framerate * encodeCompressionRatio)
if bitrate < minBitrate {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if bitrate < minBitrate {
// this accounts for zero bitrates too
if bitrate < minBitrate {

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good, added comment.

// We walk the updated set of `videoSources` and ensure all of the sources are "created" and
// "started".
config := gostream.StreamConfig{
Name: name,
VideoEncoderFactory: server.streamConfig.VideoEncoderFactory,
TargetFrameRate: framerate,
Copy link
Member

Choose a reason for hiding this comment

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

What happens if this is 0? Can we add a test?

Copy link
Member Author

Choose a reason for hiding this comment

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

encoder pipeline will default to 30fps in bitrate calculation (the same as the key-frame interval) if it cant pick up framerate.

Will see about adding a test for this.


// calcBitrateFromResolution calculates the bitrate based on the given resolution and framerate.
func calcBitrateFromResolution(width, height int, framerate float32) int {
bitrate := int(float32(width) * float32(height) * framerate * encodeCompressionRatio)
Copy link
Member

Choose a reason for hiding this comment

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

Does bitrate scale linearly with width and height? Apparently the answer is complicated https://www.reddit.com/r/explainlikeimfive/comments/hlrwcu/eli5_what_is_the_relationship_between_bit_rate/

Copy link
Member Author

@seanavery seanavery Feb 3, 2025

Choose a reason for hiding this comment

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

I am currently scaling the bitrate linearly with the number of pixels.

Interesting graphs in the thread that show logarithmic quality gains with increasing bitrate for a given size/fps. Will try to verify that we are hitting these sweet-spots. The amount of scene change also comes into play here so it gets quite complicated.

Copy link
Member Author

Choose a reason for hiding this comment

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

If you look at the example bitrates in the description we seem to be pretty bang on to the recommended settings linked in the jira ticket: https://support.google.com/youtube/answer/2853702?hl=en

@@ -507,11 +507,16 @@ func (server *Server) AddNewStreams(ctx context.Context) error {
server.logger.Warn("video streaming not supported on Windows yet")
break
}
framerate, err := server.getFramerateFromCamera(name)
Copy link
Member

Choose a reason for hiding this comment

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

will this new logic break streaming for cameras that don't provide framerate in getProperties?

Copy link
Member Author

@seanavery seanavery Feb 3, 2025

Choose a reason for hiding this comment

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

Will add comment here -- encoder pipeline will default to 30fps in bitrate calculation (the same as the key-frame interval) if it cant pick up framerate.

@hexbabe hexbabe self-requested a review February 3, 2025 19:18
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 3, 2025
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
safe to test This pull request is marked safe to test from a trusted zone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants