Rust视频处理库ez-ffmpeg的使用:简化FFmpeg集成与高效音视频编解码

Rust视频处理库ez-ffmpeg的使用:简化FFmpeg集成与高效音视频编解码

Logo

概述

ez-ffmpeg提供了一个安全且符合人体工程学的Rust接口用于FFmpeg集成,提供了一个熟悉的API,紧密遵循FFmpeg的原始逻辑和参数结构。

这个库:

  • 确保完全安全而不使用unsafe代码
  • 保持执行逻辑和参数约定尽可能接近FFmpeg
  • 提供一个直观和用户友好的API进行媒体处理
  • 支持自定义Rust过滤器和灵活的输入/输出处理
  • 提供可选的RTMP和OpenGL集成

通过抽象原始C API的复杂性,ez-ffmpeg简化了配置媒体管道、执行转码和过滤以及检查媒体流的过程。

版本要求

  • Rust: 版本1.80.0或更高
  • FFmpeg: 版本7.0或更高

快速开始

安装前提条件

macOS

brew install ffmpeg

Windows

# 动态链接
vcpkg install ffmpeg

# 静态链接(需要'static'功能)
vcpkg install ffmpeg:x64-windows-static-md

# 设置VCPKG_ROOT环境变量

添加依赖

将ez-ffmpeg添加到您的项目中,包含在您的Cargo.toml中:

[dependencies]
ez-ffmpeg = "*"

基本用法

以下是一个基本示例帮助您开始。创建或更新您的main.rs如下代码:

use ez_ffmpeg::FfmpegContext;
use ez_ffmpeg::FfmpegScheduler;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 构建FFmpeg上下文
    let context = FfmpegContext::builder()
        .input("input.mp4")
        .filter_desc("hue=s=0") // 示例过滤器: desaturate (可选)
        .output("output.mov")
        .build()?;

    // 2. 通过FfmpegScheduler运行(同步模式)
    let result = FfmpegScheduler::new(context)
        .start()?
        .wait();
    result?; // 传播发生的任何错误
    Ok(())
}

完整示例代码

下面是一个更完整的示例,展示了如何使用ez-ffmpeg进行视频转码和添加水印:

use ez_ffmpeg::FfmpegContext;
use ez_ffmpeg::FfmpegScheduler;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 构建FFmpeg处理管道
    let context = FfmpegContext::builder()
        // 输入视频文件
        .input("input.mp4")
        
        // 视频过滤器链
        // 1. 缩放视频到720p
        // 2. 添加水印(logo.png在右上角)
        .filter_desc("[0:v]scale=1280:720[scaled]; \
                     [scaled][1:v]overlay=W-w-10:10")
        
        // 添加水印图片
        .input("logo.png")
        
        // 音频过滤器(可选)
        .filter_desc("[0:a]volume=0.8[a]")
        
        // 输出设置
        .output("output.mp4")
            .video_codec("libx264")  // 使用x264编码
            .audio_codec("aac")      // 使用AAC音频
            .bitrate("2000k")        // 视频比特率
            .framerate(30)           // 输出帧率
            .preset("fast")          // x264预设
            .build_output()?
        
        // 构建整个上下文
        .build()?;

    // 运行处理
    let scheduler = FfmpegScheduler::new(context);
    let handle = scheduler.start()?;
    
    // 等待处理完成
    let result = handle.wait();
    match result {
        Ok(_) => println!("视频处理成功完成!"),
        Err(e) => eprintln!("处理失败: {}", e),
    }
    
    Ok(())
}

特性

ez-ffmpeg提供了几个可选特性,可以在您的Cargo.toml中根据需要启用:

  • opengl: 启用GPU加速的OpenGL过滤器以进行高性能视频处理
  • rtmp: 包括一个嵌入式RTMP服务器用于本地流媒体场景
  • flv: 提供对FLV容器解析和处理的支持
  • async: 添加异步功能(允许您.await操作)
  • static: 启用FFmpeg库的静态链接(通过ffmpeg-next/static)

许可证

ez-ffmpeg根据您的选择获得MIT、Apache-2.0或MPL-2.0许可证的许可。您可以选择最适合您需求的许可证。 重要说明: 虽然ez-ffmpeg可以自由使用,但FFmpeg有自己的许可条款。确保您对其组件的使用符合FFmpeg的许可证。


1 回复

Rust视频处理库ez-ffmpeg的使用:简化FFmpeg集成与高效音视频编解码

介绍

ez-ffmpeg是一个Rust语言的FFmpeg绑定库,旨在简化FFmpeg在Rust项目中的集成和使用。它提供了高级API抽象,让开发者能够更轻松地进行音视频编解码、处理和分析,而无需直接处理复杂的FFmpeg底层API。

主要特性

  • 简化的FFmpeg API接口
  • 安全的Rust绑定
  • 支持音视频编解码
  • 流处理功能
  • 元数据访问
  • 格式转换

安装方法

在Cargo.toml中添加依赖:

[dependencies]
ez-ffmpeg = "0.1"

确保系统已安装FFmpeg开发库(Linux上通常为libavcodec-dev, libavformat-dev等)。

基本使用方法

1. 打开媒体文件

use ez_ffmpeg::format::input;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut input_ctx = input("input.mp4")?;
    println!("文件格式: {}", input_ctx.format());
    
    Ok(())
}

2. 解码视频流

use ez_ffmpeg::{format::input, codec::decoder::video::VideoDecoder};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut input_ctx = input("input.mp4")?;
    let video_stream = input_ctx.streams().video().nth(0).unwrap();
    let mut decoder = VideoDecoder::from_stream(video_stream)?;
    
    for packet in video_stream.packets() {
        let frame = decoder decode(&packet)?;
        println!("解码帧: {}x{}", frame.width(), frame.height());
    }
    
    Ok(())
}

3. 转码视频文件

use ez_ffmpeg::{
    format::{input, output},
    codec::{decoder::video::VideoDecoder, encoder::video::VideoEncoder},
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 输入文件
    let mut input_ctx = input("input.mp4")?;
    let video_stream = input_ctx.streams().video().nth(0).unwrap();
    let mut decoder = VideoDecoder::from_stream(video_stream)?;
    
    // 输出文件
    let mut output_ctx = output("output.mkv")?;
    let mut encoder = VideoEncoder::new("libx264")?
        .width(decoder.width())
        .height(decoder.height())
        .time_base(video_stream.time_base())
        .build()?;
    
    let mut output_stream = output_ctx.add_stream(&encoder)?;
    
    // 处理每一帧
    for packet in video_stream.packets() {
        let frame = decoder.decode(&packet)?;
        let encoded_packet = encoder.encode(&frame)?;
        output_stream.write(&encoded_packet)?;
    }
    
    output_ctx.write_trailer()?;
    
    Ok(())
}

4. 提取音频

use ez_ffmpeg::{
    format::{input, output},
    codec::decoder::audio::AudioDecoder,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut input_ctx = input("input.mp4")?;
    let audio_stream = input_ctx.streams().audio().nth(0).unwrap();
    let mut decoder = AudioDecoder::from_stream(audio_stream)?;
    
    let mut output_ctx = output("audio_only.mp3")?;
    let mut output_stream = output_ctx.add_stream(&decector)?;
    
    for packet in audio_stream.packets() {
        let frame = decoder.decode(&packet)?;
        output_stream.write(&frame)?;
    }
    
    output_ctx.write_trailer()?;
    
    Ok(())
}

高级功能

1. 视频滤镜处理

use ez_ffmpeg::{
    format::input,
    filter::Graph,
    codec::decoder::video::VideoDecoder,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut input_ctx = input("input.mp4")?;
    let video_stream = input_ctx.streams().video().nth(0).unwrap();
    let mut decoder = VideoDecoder::from_stream(video_stream)?;
    
    // 创建滤镜图:缩放+旋转
    let mut filter_graph = Graph::new();
    filter_graph
        .add_input("in", decoder.parameters())?
        .add_output("out")?
        .parse("scale=640:480,rotate=30*PI/180")?;
    
    for packet in video_stream.packets() {
        let frame = decoder.decode(&packet)?;
        let filtered_frames = filter_graph.process("in", frame)?;
        
        for filtered_frame in filtered_frames {
            println!("处理后的帧: {:?}", filtered_frame);
        }
    }
    
    Ok(())
}

2. 硬件加速解码

use ez_ffmpeg::{
    format::input,
    codec::decoder::video::VideoDecoder,
    hardware::DeviceType,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut input_ctx = input("input.mp4")?;
    let video_stream = input_ctx.streams().video().nth(0).unwrap();
    
    // 使用CUDA硬件加速
    let mut decoder = VideoDecoder::from_stream(video_stream)?
        .hardware_device(DeviceType::CUDA)?
        .build()?;
    
    for packet in video_stream.packets() {
        let frame = decoder.decode(&packet)?;
        println!("硬件解码帧: {:?}", frame);
    }
    
    Ok(())
}

完整示例

下面是一个完整的视频转码示例,包含错误处理和硬件加速:

use ez_ffmpeg::{
    format::{input, output},
    codec::{decoder::video::VideoDecoder, encoder::video::VideoEncoder},
    hardware::DeviceType,
    Error,
};

fn transcode_video(input_path: &str, output_path: &str) -> Result<(), Error> {
    // 打开输入文件
    let mut input_ctx = input(input_path)?;
    let video_stream = input_ctx.streams().video().nth(0).ok_or("No video stream found")?;
    
    // 使用硬件加速解码器
    let mut decoder = VideoDecoder::from_stream(video_stream)?
        .hardware_device(DeviceType::CUDA)?
        .build()?;
    
    // 准备输出文件
    let mut output_ctx = output(output_path)?;
    let mut encoder = VideoEncoder::new("libx264")?
        .width(decoder.width())
        .height(decoder.height())
        .time_base(video_stream.time_base())
        .build()?;
    
    let mut output_stream = output_ctx.add_stream(&encoder)?;
    
    // 处理每一帧
    for packet in video_stream.packets() {
        let frame = decoder.decode(&packet)?;
        let encoded_packet = encoder.encode(&frame)?;
        output_stream.write(&encoded_packet)?;
    }
    
    // 写入文件尾
    output_ctx.write_trailer()?;
    
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    transcode_video("input.mp4", "output.mkv")?;
    println!("视频转码完成!");
    Ok(())
}

注意事项

  1. 确保系统已正确安装FFmpeg库
  2. 处理大文件时注意内存管理
  3. 错误处理很重要,FFmpeg操作可能会因各种原因失败
  4. 多线程环境下需要正确处理上下文

ez-ffmpeg通过提供更符合Rust习惯的API,大大降低了使用FFmpeg进行音视频处理的复杂度,同时保持了FFmpeg强大的功能特性。

回到顶部