#codec #ffmpeg #decoding #muxing #encoding

video-rs

基于ffmpeg的高级别视频工具包

28个版本 (7个重大变更)

0.8.1 2024年5月14日
0.7.4 2024年4月29日
0.7.2 2024年3月27日
0.5.0 2023年11月10日
0.1.6 2022年11月29日

#17 in 视频

Download history 447/week @ 2024-05-04 560/week @ 2024-05-11 342/week @ 2024-05-18 311/week @ 2024-05-25 189/week @ 2024-06-01 288/week @ 2024-06-08 252/week @ 2024-06-15 423/week @ 2024-06-22 382/week @ 2024-06-29 373/week @ 2024-07-06 330/week @ 2024-07-13 393/week @ 2024-07-20 545/week @ 2024-07-27 520/week @ 2024-08-03 656/week @ 2024-08-10 271/week @ 2024-08-17

2,108次每月下载
4 crate中使用

MIT/Apache

135KB
2.5K SLoC

video-rs

基于ffmpeg的高级别视频工具包。

🎬 简介

video-rs是一个通用的Rust视频库,它使用来自ffmpeglibav家族库。它旨在提供稳定且Rust风格的接口,用于许多常见的视频任务,如读取、写入、复用、编码和解码。

🛠 状态

⚠️ 此项目仍在开发中,可能包含错误。API的一些部分尚未完全实现。请谨慎使用。

还可以查看我们的其他视频/音频项目raverave仍在开发中,但最终目标是取代video-rs并提供一个无需依赖ffmpeg的完整功能媒体库。

📦 设置

首先,安装ffmpeg库。ffmpeg-next项目在这方面有优秀的说明video-rs依赖于ffmpeg-next crate)。

然后,将以下内容添加到您的Cargo.toml依赖项中

video-rs = "0.8"

使用ndarray功能来使用原始帧,并使用ndarray crate

video-rs = { version = "0.8", features = ["ndarray"] }

📖 示例

解码视频并打印左上角像素的RGB值

use video_rs::decode::Decoder;
use video_rs::Url;

fn main() {
    video_rs::init().unwrap();

    let source =
        "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
            .parse::<Url>()
            .unwrap();
    let mut decoder = Decoder::new(source).expect("failed to create decoder");

    for frame in decoder.decode_iter() {
        if let Ok((_, frame)) = frame {
            let rgb = frame.slice(ndarray::s![0, 0, ..]).to_slice().unwrap();
            println!("pixel at 0, 0: {}, {}, {}", rgb[0], rgb[1], rgb[2],);
        } else {
            break;
        }
    }
}

使用ndarray创建每个帧并编码🌈视频

use std::path::Path;

use ndarray::Array3;

use video_rs::encode::{Encoder, Settings};
use video_rs::time::Time;

fn main() {
    video_rs::init().unwrap();

    let settings = Settings::preset_h264_yuv420p(1280, 720, false);
    let mut encoder =
        Encoder::new(Path::new("rainbow.mp4"), settings).expect("failed to create encoder");

    let duration: Time = Time::from_nth_of_a_second(24);
    let mut position = Time::zero();
    for i in 0..256 {
        // This will create a smooth rainbow animation video!
        let frame = rainbow_frame(i as f32 / 256.0);

        encoder
            .encode(&frame, &position)
            .expect("failed to encode frame");

        // Update the current position and add the inter-frame duration to it.
        position = position.aligned_with(&duration).add();
    }

    encoder.finish().expect("failed to finish encoder");
}

fn rainbow_frame(p: f32) -> Array3<u8> {
    // This is what generated the rainbow effect! We loop through the HSV color spectrum and convert
    // to RGB.
    let rgb = hsv_to_rgb(p * 360.0, 100.0, 100.0);

    // This creates a frame with height 720, width 1280 and three channels. The RGB values for each
    // pixel are equal, and determined by the `rgb` we chose above.
    Array3::from_shape_fn((720, 1280, 3), |(_y, _x, c)| rgb[c])
}

fn hsv_to_rgb(h: f32, s: f32, v: f32) -> [u8; 3] {
    let s = s / 100.0;
    let v = v / 100.0;
    let c = s * v;
    let x = c * (1.0 - (((h / 60.0) % 2.0) - 1.0).abs());
    let m = v - c;
    let (r, g, b) = if (0.0..60.0).contains(&h) {
        (c, x, 0.0)
    } else if (60.0..120.0).contains(&h) {
        (x, c, 0.0)
    } else if (120.0..180.0).contains(&h) {
        (0.0, c, x)
    } else if (180.0..240.0).contains(&h) {
        (0.0, x, c)
    } else if (240.0..300.0).contains(&h) {
        (x, 0.0, c)
    } else if (300.0..360.0).contains(&h) {
        (c, 0.0, x)
    } else {
        (0.0, 0.0, 0.0)
    };
    [
        ((r + m) * 255.0) as u8,
        ((g + m) * 255.0) as u8,
        ((b + m) * 255.0) as u8,
    ]
}

🪲 调试

Ffmpeg并不总是直接产生有用的错误消息。如果您遇到问题,建议开启跟踪以查看日志消息中是否包含额外信息。

将以下包添加到 Cargo.toml

[dependencies]
tracing = "0.1"
tracing-subscriber = "0.3"

并在你的主函数中添加以下内容

fn main() {
    tracing_subscriber::fmt::init();

    // ...
}

设置环境变量 RUST_LOG 以显示跟踪消息

RUST_LOG=video=debug cargo run

✨ 致谢

video-rs 的存在归功于以下组织和人员

⚖️ 许可证

在以下许可证中选择一项

任选其一。

贡献

除非你明确声明,否则根据 Apache-2.0 许可证定义的,任何有意提交给工作以包含在你所做的工作中的贡献,都将如上双重许可,不附加任何额外条款或条件。

依赖

~2–5MB
~118K SLoC