feat(step-down): the bitrate floor is the tier's YouTube minimum
Step-down used a flat 3 Mbps (4 for vertical) as its floor — a number that had nothing to do with the tier being streamed. With CBR holding the target, that floor is a real picture-quality floor, so it has to follow YouTube's published H.264 table (support.google.com/youtube/answer/2853702): 6 at 1080p60, 5 at 1080p30, 3 at 720p. Models/RateLadder is that table as pure policy. Vertical is not a separate row: 1080x1920 and 1920x1080 are the same pixel count, so the frame rate alone picks the band. StepDownPolicy takes the floor as an optional constructor argument and refuses one above the starting rate, so an unusual start cannot begin under its own floor. Omitted, the historical 3/4 floor still applies, which keeps the existing policy tests meaningful and lets a caller opt in. One consequence worth knowing: the three-step budget can stop above the floor (12 → 9.6 → 7.7 → 6.2 from a 20% loss), so the floor is a limit, not a target. 669 pass, 0 warnings.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
namespace ytLive.Models;
|
||||
|
||||
/// <summary>
|
||||
/// YouTube's published H.264 ingestion numbers for a tier, in Mbps — the floor a step-down may walk
|
||||
/// to and the recommended rate a creator aims at.
|
||||
///
|
||||
/// <para><b>Source:</b> support.google.com/youtube/answer/2853702 (checked 2026-11-12): 1080p@60
|
||||
/// 6 min / 17 recommended, 1080p@30 5/14, 720p@30 and @60 3/8. The same page specifies CBR, which is
|
||||
/// why these numbers are a target the encoder actually holds (<c>FfmpegArgs.AddRateControl</c>).</para>
|
||||
///
|
||||
/// <para><b>Vertical is not a separate row.</b> 1080×1920 has the same pixel count as 1920×1080, so a
|
||||
/// portrait tier takes the band of its landscape pair — the frame rate alone decides which row.</para>
|
||||
/// </summary>
|
||||
public static class RateLadder
|
||||
{
|
||||
/// <summary>Minimum and recommended rates for a tier.</summary>
|
||||
public readonly record struct Band(double Minimum, double Recommended);
|
||||
|
||||
public static Band For(int width, int height, int fps)
|
||||
{
|
||||
var is1080 = Math.Max(width, height) >= 1920;
|
||||
return (is1080, fps > 30) switch
|
||||
{
|
||||
(true, true) => new Band(6.0, 17.0),
|
||||
(true, false) => new Band(5.0, 14.0),
|
||||
(_, _) => new Band(3.0, 8.0),
|
||||
};
|
||||
}
|
||||
|
||||
public static Band For(QualityOption tier) => For(tier.Width, tier.Height, tier.Fps);
|
||||
}
|
||||
Reference in New Issue
Block a user