|
1 | 1 | use anyhow::Result; |
2 | 2 | use clap::Parser; |
3 | 3 | use livekit::e2ee::{key_provider::*, E2eeOptions, EncryptionType}; |
4 | | -use livekit::options::{TrackPublishOptions, VideoCodec, VideoEncoding}; |
| 4 | +use livekit::options::{self, TrackPublishOptions, VideoCodec, VideoEncoding, VideoPreset, video as video_presets}; |
5 | 5 | use livekit::prelude::*; |
6 | 6 | use livekit::webrtc::video_frame::{I420Buffer, VideoFrame, VideoRotation}; |
7 | 7 | use livekit::webrtc::video_source::native::NativeVideoSource; |
@@ -146,6 +146,7 @@ async fn run(args: Args, ctrl_c_received: Arc<AtomicBool>) -> Result<()> { |
146 | 146 | info!("Connecting to LiveKit room '{}' as '{}'...", args.room_name, args.identity); |
147 | 147 | let mut room_options = RoomOptions::default(); |
148 | 148 | room_options.auto_subscribe = true; |
| 149 | + room_options.dynacast = true; |
149 | 150 |
|
150 | 151 | // Configure E2EE if an encryption key is provided |
151 | 152 | if let Some(ref e2ee_key) = args.e2ee_key { |
@@ -220,19 +221,40 @@ async fn run(args: Args, ctrl_c_received: Arc<AtomicBool>) -> Result<()> { |
220 | 221 | let requested_codec = if args.h265 { VideoCodec::H265 } else { VideoCodec::H264 }; |
221 | 222 | info!("Attempting publish with codec: {}", requested_codec.as_str()); |
222 | 223 |
|
| 224 | + // Compute an explicit video encoding so all simulcast layers use 30 fps. |
| 225 | + // The SDK defaults reduce lower layers to 15/20 fps; we override that here. |
| 226 | + let target_fps = args.fps as f64; |
| 227 | + let main_encoding = { |
| 228 | + let base = options::compute_appropriate_encoding(false, width, height, VideoCodec::H264); |
| 229 | + VideoEncoding { |
| 230 | + max_bitrate: args.max_bitrate.unwrap_or(base.max_bitrate), |
| 231 | + max_framerate: target_fps, |
| 232 | + } |
| 233 | + }; |
| 234 | + let simulcast_presets = compute_simulcast_presets_30fps(width, height, target_fps); |
| 235 | + info!( |
| 236 | + "Video encoding: {}x{} @ {:.0} fps, {} bps (simulcast layers: {})", |
| 237 | + width, |
| 238 | + height, |
| 239 | + target_fps, |
| 240 | + main_encoding.max_bitrate, |
| 241 | + simulcast_presets |
| 242 | + .iter() |
| 243 | + .map(|p| format!("{}x{}@{:.0}fps/{}bps", p.width, p.height, p.encoding.max_framerate, p.encoding.max_bitrate)) |
| 244 | + .collect::<Vec<_>>() |
| 245 | + .join(", "), |
| 246 | + ); |
| 247 | + |
223 | 248 | let publish_opts = |codec: VideoCodec| { |
224 | | - let mut opts = TrackPublishOptions { |
| 249 | + TrackPublishOptions { |
225 | 250 | source: TrackSource::Camera, |
226 | 251 | simulcast: args.simulcast, |
227 | 252 | video_codec: codec, |
228 | 253 | user_timestamp: args.attach_timestamp, |
| 254 | + video_encoding: Some(main_encoding.clone()), |
| 255 | + simulcast_layers: Some(simulcast_presets.clone()), |
229 | 256 | ..Default::default() |
230 | | - }; |
231 | | - if let Some(bitrate) = args.max_bitrate { |
232 | | - opts.video_encoding = |
233 | | - Some(VideoEncoding { max_bitrate: bitrate, max_framerate: args.fps as f64 }); |
234 | 257 | } |
235 | | - opts |
236 | 258 | }; |
237 | 259 |
|
238 | 260 | let publish_result = room |
@@ -486,3 +508,19 @@ async fn run(args: Args, ctrl_c_received: Arc<AtomicBool>) -> Result<()> { |
486 | 508 |
|
487 | 509 | Ok(()) |
488 | 510 | } |
| 511 | + |
| 512 | +/// Build simulcast presets that match the SDK defaults but with a uniform frame rate. |
| 513 | +/// The SDK's built-in `DEFAULT_SIMULCAST_PRESETS` use 15/20 fps for lower layers; |
| 514 | +/// this keeps the same resolutions and bitrates but overrides fps to `target_fps`. |
| 515 | +fn compute_simulcast_presets_30fps(width: u32, height: u32, target_fps: f64) -> Vec<VideoPreset> { |
| 516 | + let ar = width as f32 / height as f32; |
| 517 | + let defaults: &[VideoPreset] = if f32::abs(ar - 16.0 / 9.0) < f32::abs(ar - 4.0 / 3.0) { |
| 518 | + video_presets::DEFAULT_SIMULCAST_PRESETS |
| 519 | + } else { |
| 520 | + livekit::options::video43::DEFAULT_SIMULCAST_PRESETS |
| 521 | + }; |
| 522 | + defaults |
| 523 | + .iter() |
| 524 | + .map(|p| VideoPreset::new(p.width, p.height, p.encoding.max_bitrate, target_fps)) |
| 525 | + .collect() |
| 526 | +} |
0 commit comments