Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/av1-packet-trailers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
webrtc-sys: patch
libwebrtc: patch
livekit: patch
livekit-ffi: patch
---

Fix AV1 subscriber decode when packet trailers are enabled.
7 changes: 7 additions & 0 deletions .changeset/local-video-pipeline-timing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
webrtc-sys: patch
libwebrtc: patch
livekit: patch
---

Add native video pipeline timing instrumentation for local video publisher measurements.
4 changes: 2 additions & 2 deletions examples/local_video/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Publisher usage:
--room-name demo \
--identity cam-1 \
--simulcast \
--h265 \
--codec h265 \
--max-bitrate 1500000 \
--url https://your.livekit.server \
--api-key YOUR_KEY \
Expand Down Expand Up @@ -89,7 +89,7 @@ Publisher flags (in addition to the common connection flags above):
- `--width <px>`: Desired capture width (default: `1280`).
- `--height <px>`: Desired capture height (default: `720`).
- `--fps <n>`: Desired capture framerate (default: `30`).
- `--h265`: Use H.265/HEVC encoding if supported (falls back to H.264 on failure).
- `--codec <codec>`: Video codec to use for publishing: `h264`, `h265`, `vp8`, `vp9`, or `av1` (default: `h264`). H.265 falls back to H.264 on failure.
- `--simulcast`: Publish simulcast video (multiple layers when the resolution is large enough).
- `--max-bitrate <bps>`: Max video bitrate for the main (highest) layer in bits per second (e.g. `1500000`).
- `--attach-timestamp`: Attach the current wall-clock time (microseconds since UNIX epoch) as the user timestamp on each published frame. The subscriber can display this to measure end-to-end latency.
Expand Down
67 changes: 67 additions & 0 deletions examples/local_video/src/codec_display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#[allow(dead_code)]
pub(crate) fn codec_from_mime(mime: &str) -> String {
let base = mime.split(';').next().unwrap_or(mime).trim();
let last = base.rsplit('/').next().unwrap_or(base).trim();
last.to_ascii_uppercase()
}

pub(crate) fn codec_with_implementation(codec: &str, implementation: &str) -> String {
let codec = if codec.is_empty() { "Unknown" } else { codec };
let Some(implementation) = implementation_label(implementation) else {
return codec.to_string();
};

format!("{codec} {implementation}")
}

fn implementation_label(implementation: &str) -> Option<String> {
let implementation = implementation.trim();
if implementation.is_empty() {
return None;
}

let lower = implementation.to_ascii_lowercase();
if lower.contains("nvidia") {
return Some(if lower.contains("decoder") { "NVDEC" } else { "NVENC" }.to_string());
}
if lower.contains("vaapi") {
return Some("VAAPI".to_string());
}
if lower.contains("videotoolbox") {
return Some("VideoToolbox".to_string());
}
if lower.contains("openh264") {
return Some("OpenH264".to_string());
}
if lower.contains("libvpx") {
return Some("libvpx".to_string());
}
if lower.contains("libaom") {
return Some("libaom".to_string());
}

Some(
implementation
.strip_suffix(" Encoder")
.or_else(|| implementation.strip_suffix(" Decoder"))
.unwrap_or(implementation)
.to_string(),
)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn extracts_codec_from_mime_type() {
assert_eq!(codec_from_mime("video/H264;profile-level-id=42e01f"), "H264");
}

#[test]
fn shortens_common_hardware_implementations() {
assert_eq!(codec_with_implementation("H264", "NVIDIA H264 Encoder"), "H264 NVENC");
assert_eq!(codec_with_implementation("H265", "VAAPI H264 Encoder"), "H265 VAAPI");
assert_eq!(codec_with_implementation("H264", "NVIDIA H264 Decoder"), "H264 NVDEC");
}
}
Loading