Skip to content

Dc/exp/lkcapture#1210

Draft
chenosaurus wants to merge 25 commits into
mainfrom
dc/exp/lkcapture
Draft

Dc/exp/lkcapture#1210
chenosaurus wants to merge 25 commits into
mainfrom
dc/exp/lkcapture

Conversation

@chenosaurus

Copy link
Copy Markdown
Contributor

Before you submit your PR

Make sure the following is true before submitting your PR:

  • I have read the contributing guidelines and validated that this PR will be accepted.
  • I have read and followed the principles regarding breaking changes, testing, and code quality.

PR description

Describe the changes in this PR. Explain what the PR is meant to solve and how to reproduce the issue in the first place.

Breaking changes

If this PR introduces breaking changes, list them here and document the rationale for introducing such a change.

MSRV

If the PR modifies the crate's MSRV (Minimum Supported Rust Version), document it here.

Testing

Ideally, unit test the code you add, but ensure you're not repeating existing test cases. Use as many already written scaffolding, utilities as possible; write your own, when needed. If external services, APIs, tokens are required (e.g., running an LK server instance), provide the necessary information. Make sure your tests perform useful, context-aware assertions and do not simply emulate "happy paths".

Async

We want the project to be runtime-agnostic, so please reuse what's already in livekit-runtime and feel free to add anything missing. It's ok to use Tokio directly, when writing unit tests, if necessary. When testing, do not use artificial delays for the state to "catch up"; instead, respect the event flow and subscribe properly using channels or other mechanisms.

@ladvoc ladvoc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left some initial comments on the capture components, off to a great start!

Maybe we should break out the changes to libwebrtc and webrtc-sys into their own PRs?

Comment thread livekit-capture/build.rs
fn main() {
println!("cargo:rustc-check-cfg=cfg(livekit_capture_argus)");
println!("cargo:rerun-if-env-changed=JETSON_MULTIMEDIA_API_DIR");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This might need to explicitly link Objective-C for Apple platforms when this is compiled outside of the workspace:

Suggested change
match std::env::var("CARGO_CFG_TARGET_OS").as_deref() {
Ok("macos") | Ok("ios") => println!("cargo:rustc-link-arg=-ObjC"),
_ => {}
}

// limitations under the License.

//! Capture helpers for publishing decoded, DMA-BUF, and encoded video with LiveKit.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Add contents of README as module level doc comment so it appears in generated docs:

Suggested change
#![doc = include_str!("../README.md")]

pub(crate) mod time;
pub mod track;

pub use device::{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Instead of exporting everything at the top-level, consider exporting a prelude module that includes the types most consumers will be interested in that they can import as a wildcard. This pattern is used in the livekit crate currently.

Comment thread livekit-capture/README.md

## Pre-encoded test sources

The example ships GStreamer fixture scripts that exercise the H.264, H.265,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This should link to the example in GitHub since it wouldn't be clear to someone discovering this crate through crates.io which example it is referring to.

}
}

fn stats_poll_interval() -> Duration {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nitpick: Define this as a const.


impl CaptureFormat {
/// Creates a raw-frame capture format.
pub const fn new(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This should be removed since this struct has public fields and nothing is computed here.


/// H.264 packetization mode for passthrough metadata.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum H264PacketizationMode {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: It looks like it might be necessary to add an interleaved case in the future? If so, this should be marked #[non_exhaustive].

Comment on lines +113 to +130
let mut scratch = Vec::new();
let payload: &[u8] = match &access_unit.payload {
EncodedPayload::Contiguous(bytes) => bytes,
EncodedPayload::Owned(bytes) => bytes,
EncodedPayload::Fragments(_) => {
scratch = access_unit.payload.to_vec();
&scratch
}
};
let frame = EncodedVideoFrame {
codec: access_unit.codec.into(),
payload,
timestamp_us: access_unit.timestamp_us,
frame_type: access_unit.frame_type.into(),
width: access_unit.width,
height: access_unit.height,
frame_metadata: None,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider rewriting using Cow:

Suggested change
let mut scratch = Vec::new();
let payload: &[u8] = match &access_unit.payload {
EncodedPayload::Contiguous(bytes) => bytes,
EncodedPayload::Owned(bytes) => bytes,
EncodedPayload::Fragments(_) => {
scratch = access_unit.payload.to_vec();
&scratch
}
};
let frame = EncodedVideoFrame {
codec: access_unit.codec.into(),
payload,
timestamp_us: access_unit.timestamp_us,
frame_type: access_unit.frame_type.into(),
width: access_unit.width,
height: access_unit.height,
frame_metadata: None,
};
let payload: Cow<'_, [u8]> = match &access_unit.payload {
EncodedPayload::Contiguous(bytes) => Cow::Borrowed(bytes),
EncodedPayload::Owned(bytes) => Cow::Borrowed(bytes),
EncodedPayload::Fragments(_) => Cow::Owned(access_unit.payload.to_vec()),
};
let frame = EncodedVideoFrame {
codec: access_unit.codec.into(),
payload: &payload,
timestamp_us: access_unit.timestamp_us,
frame_type: access_unit.frame_type.into(),
width: access_unit.width,
height: access_unit.height,
frame_metadata: None,
};

let shutdown_stream = stream.try_clone().context("failed to clone TCP stream")?;
let source = TcpEncodedSource::from_tcp_stream(stream, config)?;

publish_encoded_source(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This is hard to read at the call site; consider breaking out args into a separate struct (i.e., PublishEncodedSourceOptions).

);

log::info!("Connecting to TCP {wire_format:?} encoded stream at {host}");
let stream = TcpStream::connect(&host)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue: This blocks the async runtime; use the async variant of connect provided by tokio and allow the reset of the connection to be sync:

let stream = tokio::time::timeout(TCP_CONNECT_TIMEOUT, tokio::net::TcpStream::connect(&host))
    .await??;
    .with_context(|| format!("timed out connecting to TCP source at {host}"))?
    .with_context(|| format!("failed to connect to TCP source at {host}"))?;

let stream = stream.into_std().context("failed to convert TCP stream to blocking")?;
stream.set_nonblocking(false).context("failed to set TCP stream to blocking mode")?;

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.

2 participants