Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
833 changes: 94 additions & 739 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ license = "MIT"
crate-type = ["lib"]

[dependencies]
anyhow = "1.0.79"
ureq = { version = "2.10.1", optional = true }
anyhow = "1.0.98"
ureq = { version = "3.0.12", optional = true }

[features]
default = ["download_ffmpeg"]
download_ffmpeg = ["dep:ureq", "dep:tar", "dep:xz2", "dep:zip"]
named_pipes = ["dep:winapi", "dep:nix"]

[target.'cfg(target_os = "linux")'.dependencies]
tar = { version = "0.4.42", optional = true }
tar = { version = "0.4.44", optional = true }
xz2 = { version = "0.1.7", optional = true }

[target.'cfg(not(target_os = "linux"))'.dependencies]
zip = { version = "2.3.0", optional = true }
zip = { version = "4.3.0", optional = true, default-features = false, features = ["deflate"] }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", optional = true, features = [
Expand All @@ -38,9 +38,7 @@ winapi = { version = "0.3.9", optional = true, features = [
] }

[target.'cfg(unix)'.dependencies]
nix = { version = "0.29.0", optional = true, features = [
"fs"
] }
nix = { version = "0.30.1", optional = true, features = ["fs"] }

[package.metadata.docs.rs]
all-features = true
Expand Down
8 changes: 4 additions & 4 deletions examples/download_ffmpeg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn main() -> anyhow::Result<()> {
// Checking the version number before downloading is actually not necessary,
// but it's a good way to check that the download URL is correct.
match check_latest_version() {
Ok(version) => println!("Latest available version: {}", version),
Ok(version) => println!("Latest available version: {version}"),
Err(_) => println!("Skipping version check on this platform."),
}

Expand All @@ -38,17 +38,17 @@ fn main() -> anyhow::Result<()> {
// The built-in download function uses `reqwest` to download the package.
// For more advanced use cases like async streaming or download progress
// updates, you could replace this with your own download function.
println!("Downloading from: {:?}", download_url);
println!("Downloading from: {download_url:?}");
let archive_path = download_ffmpeg_package(download_url, &destination)?;
println!("Downloaded package: {:?}", archive_path);
println!("Downloaded package: {archive_path:?}");

// Extraction uses `tar` on all platforms (available in Windows since version 1803)
println!("Extracting...");
unpack_ffmpeg(&archive_path, &destination)?;

// Use the freshly installed FFmpeg to check the version number
let version = ffmpeg_version_with_path(destination.join("ffmpeg"))?;
println!("FFmpeg version: {}", version);
println!("FFmpeg version: {version}");

println!("Done! 🏁");
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion examples/ffprobe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() {

// Try running the executable and printing the version number.
let version = ffprobe_version().unwrap();
println!("ffprobe version: {}", version);
println!("ffprobe version: {version}");
}

#[cfg(not(feature = "download_ffmpeg"))]
Expand Down
8 changes: 4 additions & 4 deletions examples/h265_transcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ fn main() {

// On the main thread, run the output instance to completion
output.iter().unwrap().for_each(|e| match e {
FfmpegEvent::Log(LogLevel::Error, e) => println!("Error: {}", e),
FfmpegEvent::Log(LogLevel::Error, e) => println!("Error: {e}"),
FfmpegEvent::Progress(p) => println!("Progress: {} / 00:00:15", p.time),
_ => {}
});
}

/// Create a H265 source video from scratch
fn create_h265_source(path_str: &str) {
println!("Creating H265 source video: {}", path_str);
println!("Creating H265 source video: {path_str}");
FfmpegCommand::new()
.args("-f lavfi -i testsrc=size=600x800:rate=30:duration=15 -c:v libx265".split(' '))
.arg(path_str)
Expand All @@ -79,9 +79,9 @@ fn create_h265_source(path_str: &str) {
.iter()
.unwrap()
.for_each(|e| match e {
FfmpegEvent::Log(LogLevel::Error, e) => println!("Error: {}", e),
FfmpegEvent::Log(LogLevel::Error, e) => println!("Error: {e}"),
FfmpegEvent::Progress(p) => println!("Progress: {} / 00:00:15", p.time),
_ => {}
});
println!("Created H265 source video: {}", path_str);
println!("Created H265 source video: {path_str}");
}
8 changes: 4 additions & 4 deletions examples/mic_meter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ffmpeg_sidecar::{
command::FfmpegCommand,
event::{FfmpegEvent, LogLevel},
};
use std::{cmp::max, iter::repeat};
use std::cmp::max;

/// Process microphone audio data in realtime and display a volume meter/level
/// indicator rendered to the terminal.
Expand All @@ -21,7 +21,7 @@ pub fn main() -> Result<()> {

let audio_device = FfmpegCommand::new()
.hide_banner()
.args(&["-list_devices", "true"])
.args(["-list_devices", "true"])
.format("dshow")
.input("dummy")
.spawn()?
Expand All @@ -32,7 +32,7 @@ pub fn main() -> Result<()> {
.context("No audio device found")?
.context("Failed to parse audio device")?;

println!("Listening to audio device: {}", audio_device);
println!("Listening to audio device: {audio_device}");

// Second step: Capture audio and analyze w/ `ebur128` audio filter
// Loudness metadata will be printed to the FFmpeg logs
Expand Down Expand Up @@ -88,7 +88,7 @@ pub fn main() -> Result<()> {
println!(
"{} {} {}%",
recording_indicator,
repeat('█').take(volume_normalized).collect::<String>(),
"█".repeat(volume_normalized),
volume_percent
);
}
Expand Down
3 changes: 1 addition & 2 deletions examples/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ fn main() {
let duration = 10;
let total_frames = fps * duration;
let arg_string = format!(
"-f lavfi -i testsrc=duration={}:size=1920x1080:rate={} -y output/test.mp4",
duration, fps
"-f lavfi -i testsrc=duration={duration}:size=1920x1080:rate={fps} -y output/test.mp4"
);
FfmpegCommand::new()
.args(arg_string.split(' '))
Expand Down
2 changes: 1 addition & 1 deletion examples/sockets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn main() -> Result<()> {

// _ => {}
e => {
println!("{:?}", e);
println!("{e:?}");
}
});
exit_sender.send(())?;
Expand Down
10 changes: 5 additions & 5 deletions examples/trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ fn main() {
.run(Image);

let my_string = Trigger::<String, String>::new()
.map(|x| format!("({})", x))
.map(|x| format!("[{}]", x))
.map(|x| format!("{}!", x))
.map(|x| format!("({x})"))
.map(|x| format!("[{x}]"))
.map(|x| format!("{x}!"))
.run("asdf".to_string());
println!("{}", my_string);
assert!(my_string == "[(asdf)]!");
println!("{my_string}");
assert_eq!(my_string, "[(asdf)]!");

let _trigger = Trigger::<String, String>::new();
image_trigger().run(Image);
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
# to the user in the error, instead of "error: invalid channel name '[toolchain]'".

[toolchain]
channel = "1.79" # Avoid specifying a patch version here; see https://github.com/emilk/eframe_template/issues/145
channel = "1.88" # Avoid specifying a patch version here; see https://github.com/emilk/eframe_template/issues/145
components = ["rustfmt", "clippy"]
2 changes: 1 addition & 1 deletion src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ impl FfmpegCommand {
/// The format is `'wxh'` (default - same as source).
pub fn size(&mut self, width: u32, height: u32) -> &mut Self {
self.arg("-s");
self.arg(format!("{}x{}", width, height));
self.arg(format!("{width}x{height}"));
self
}

Expand Down
17 changes: 8 additions & 9 deletions src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub fn auto_download() -> Result<()> {
/// use ffmpeg_sidecar::download::parse_macos_version;
/// let json_string = "{\"name\":\"ffmpeg\",\"type\":\"release\",\"version\":\"6.0\",...}";
/// let parsed = parse_macos_version(&json_string).unwrap();
/// assert!(parsed == "6.0");
/// assert_eq!(parsed, "6.0");
/// ```
pub fn parse_macos_version(version: &str) -> Option<String> {
version
Expand All @@ -96,7 +96,7 @@ pub fn parse_macos_version(version: &str) -> Option<String> {
/// use ffmpeg_sidecar::download::parse_linux_version;
/// let json_string = "build: ffmpeg-5.1.1-amd64-static.tar.xz\nversion: 5.1.1\n\ngcc: 8.3.0";
/// let parsed = parse_linux_version(&json_string).unwrap();
/// assert!(parsed == "5.1.1");
/// assert_eq!(parsed, "5.1.1");
/// ```
pub fn parse_linux_version(version: &str) -> Option<String> {
version
Expand All @@ -119,12 +119,11 @@ pub fn check_latest_version() -> Result<String> {
}

let manifest_url = ffmpeg_manifest_url()?;
let response = ureq::get(manifest_url)
let string = ureq::get(manifest_url)
.call()
.context("Failed to GET the latest ffmpeg version")?;

let string = response
.into_string()
.context("Failed to GET the latest ffmpeg version")?
.body_mut()
.read_to_string()
.context("Failed to read response text")?;

if cfg!(target_os = "windows") {
Expand All @@ -150,12 +149,12 @@ pub fn download_ffmpeg_package(url: &str, download_dir: &Path) -> Result<PathBuf

let archive_path = download_dir.join(filename);

let response = ureq::get(url).call().context("Failed to download ffmpeg")?;
let mut response = ureq::get(url).call().context("Failed to download ffmpeg")?;

let mut file =
File::create(&archive_path).context("Failed to create file for ffmpeg download")?;

copy(&mut response.into_reader(), &mut file)
copy(&mut response.body_mut().as_reader(), &mut file)
.context("Failed to write ffmpeg download to file")?;

Ok(archive_path)
Expand Down
2 changes: 1 addition & 1 deletion src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ pub fn spawn_stderr_thread(stderr: ChildStderr, tx: SyncSender<FfmpegEvent>) ->
}
Ok(event) => tx.send(event).ok(),
Err(e) => {
eprintln!("Error parsing ffmpeg output: {}", e);
eprintln!("Error parsing ffmpeg output: {e}");
break;
}
};
Expand Down
51 changes: 25 additions & 26 deletions src/log_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<R: Read> FfmpegLogParser<R> {
/// - `\r` (Windows, progress updates which overwrite the previous line)
pub fn parse_next_event(&mut self) -> anyhow::Result<FfmpegEvent> {
let mut buf = Vec::<u8>::new();
let bytes_read = read_until_any(&mut self.reader, &[b'\r', b'\n'], &mut buf);
let bytes_read = read_until_any(&mut self.reader, b"\r\n", &mut buf);
let line_cow = String::from_utf8_lossy(buf.as_slice());
let line = line_cow.trim();
let raw_log_message = line.to_string();
Expand Down Expand Up @@ -87,8 +87,7 @@ impl<R: Read> FfmpegLogParser<R> {
LogSection::Input(_) => Ok(FfmpegEvent::ParsedInputStream(stream)),
LogSection::Output(_) => Ok(FfmpegEvent::ParsedOutputStream(stream)),
LogSection::Other | LogSection::StreamMapping => Err(anyhow::Error::msg(format!(
"Unexpected stream specification: {}",
line
"Unexpected stream specification: {line}"
))),
}
} else if let Some(progress) = try_parse_progress(line) {
Expand Down Expand Up @@ -423,7 +422,7 @@ pub fn try_parse_stream(string: &str) -> Option<Stream> {
let indices_and_maybe_language = colon_iter
.next()?
// Remove everything inside and including square brackets
.split(|c| c == '[' || c == ']')
.split(['[', ']'])
.step_by(2)
.collect::<String>();
let mut parenthesis_iter = indices_and_maybe_language.split('(');
Expand Down Expand Up @@ -560,7 +559,7 @@ pub fn try_parse_progress(mut string: &str) -> Option<FfmpegProgress> {
.and_then(|s| {
s.strip_suffix("KiB") // FFmpeg v7.0 and later
.or_else(|| s.strip_suffix("kB")) // FFmpeg v6.0 and prior
.or_else(|| s.ends_with("N/A").then(|| "0")) // handles "N/A"
.or_else(|| s.ends_with("N/A").then_some("0")) // handles "N/A"
})?
.parse::<u32>()
.ok()?;
Expand Down Expand Up @@ -713,13 +712,13 @@ mod tests {
fn test_parse_progress_v7() {
let line = "[info] frame= 5 fps=0.0 q=-1.0 Lsize= 10KiB time=00:00:03.00 bitrate= 27.2kbits/s speed= 283x\n";
let progress = try_parse_progress(line).unwrap();
assert!(progress.frame == 5);
assert!(progress.fps == 0.0);
assert!(progress.q == -1.0);
assert!(progress.size_kb == 10);
assert!(progress.time == "00:00:03.00");
assert!(progress.bitrate_kbps == 27.2);
assert!(progress.speed == 283.0);
assert_eq!(progress.frame, 5);
assert_eq!(progress.fps, 0.0);
assert_eq!(progress.q, -1.0);
assert_eq!(progress.size_kb, 10);
assert_eq!(progress.time, "00:00:03.00");
assert_eq!(progress.bitrate_kbps, 27.2);
assert_eq!(progress.speed, 283.0);
}

/// Check for handling first progress message w/ bitrate=N/A and speed=N/A
Expand All @@ -729,13 +728,13 @@ mod tests {
let line =
"[info] frame= 0 fps=0.0 q=-0.0 size= 0kB time=00:00:00.00 bitrate=N/A speed=N/A\n";
let progress = try_parse_progress(line).unwrap();
assert!(progress.frame == 0);
assert!(progress.fps == 0.0);
assert!(progress.q == -0.0);
assert!(progress.size_kb == 0);
assert!(progress.time == "00:00:00.00");
assert!(progress.bitrate_kbps == 0.0);
assert!(progress.speed == 0.0);
assert_eq!(progress.frame, 0);
assert_eq!(progress.fps, 0.0);
assert_eq!(progress.q, -0.0);
assert_eq!(progress.size_kb, 0);
assert_eq!(progress.time, "00:00:00.00");
assert_eq!(progress.bitrate_kbps, 0.0);
assert_eq!(progress.speed, 0.0);
}

/// Check for handling progress message with no size.
Expand All @@ -744,13 +743,13 @@ mod tests {
fn test_parse_progress_no_size() {
let line = "[info] frame= 163 fps= 13 q=4.4 size=N/A time=00:13:35.00 bitrate=N/A speed=64.7x";
let progress = try_parse_progress(line).unwrap();
assert!(progress.frame == 163);
assert!(progress.fps == 13.0);
assert!(progress.q == 4.4);
assert!(progress.size_kb == 0);
assert!(progress.time == "00:13:35.00");
assert!(progress.bitrate_kbps == 0.0);
assert!(progress.speed == 64.7);
assert_eq!(progress.frame, 163);
assert_eq!(progress.fps, 13.0);
assert_eq!(progress.q, 4.4);
assert_eq!(progress.size_kb, 0);
assert_eq!(progress.time, "00:13:35.00");
assert_eq!(progress.bitrate_kbps, 0.0);
assert_eq!(progress.speed, 64.7);
}

/// Coverage for non-utf-8 bytes: https://github.com/nathanbabcock/ffmpeg-sidecar/issues/67
Expand Down
6 changes: 3 additions & 3 deletions src/read_until_any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn read_until_any<R: BufRead + ?Sized>(
let start_delims = if read == 0 {
available
.iter()
.take_while(|&&b| delims.iter().any(|&d| d == b))
.take_while(|&&b| delims.contains(&b))
.count()
} else {
0
Expand All @@ -33,7 +33,7 @@ pub fn read_until_any<R: BufRead + ?Sized>(
let first_delim_index = available
.iter()
.skip(start_delims)
.position(|&b| delims.iter().any(|&d| d == b))
.position(|&b| delims.contains(&b))
.map(|i| i + start_delims);

match first_delim_index {
Expand All @@ -55,7 +55,7 @@ pub fn read_until_any<R: BufRead + ?Sized>(
}

// Discard final trailing delimiters
if used == 0 && buf.iter().all(|&b| delims.iter().any(|&d| d == b)) {
if used == 0 && buf.iter().all(|&b| delims.contains(&b)) {
return Ok(0);
}

Expand Down
Loading
Loading