Rust FFmpeg绑定库ffmpeg-sys-next的使用,提供跨平台音视频处理与多媒体编解码功能

这是一个被废弃的ffmpeg-sys crate的分支。您可以在crates.io上找到这个crate作为ffmpeg-sys-next。

这个crate包含FFmpeg的低级绑定。您可能对高级绑定感兴趣:ffmpeg-next。

关于版本控制:主要和次要版本跟踪FFmpeg的主要和次要版本,例如,此crate的4.2.x版本已更新以支持FFmpeg的4.2.x系列。补丁级别保留用于此crate的错误修复,不跟踪FFmpeg的补丁版本。

功能标志

除了在Cargo.toml中声明的功能标志外,此crate执行各种编译时版本和功能检测,并在其他标志中公开结果。这些标志简要记录如下;运行cargo build -vv以查看更多详细信息。

  • ffmpeg_<x>_<y>标志(v4.3.2新增),例如ffmpeg_4_4,表示正在编译的FFmpeg安装至少为版本<x>.<y>。当前可用:

    • ffmpeg_3_0
    • ffmpeg_3_1
    • ffmpeg_3_2
    • ffmpeg_3_3
    • ffmpeg_3_1
    • ffmpeg_4_0
    • ffmpeg_4_1
    • ffmpeg_4_2
    • ffmpeg_4_3
    • ffmpeg_4_4
  • avcodec_version_greater_than_<x>_<y>(v4.3.2新增),例如,avcodec_version_greater_than_58_90。名称应自解释。

  • ff_api_<feature>,例如ff_api_vaapi,对应于它们各自的大写弃用保护是否评估为真。

  • ff_api_<feature>_is_defined,例如ff_api_vappi_is_defined,类似于上述,但仅在相应的弃用保护已定义时启用。

以下是一个使用ffmpeg-sys-next的基本示例:

use ffmpeg_sys_next::*;

fn main() {
    // 初始化FFmpeg库
    unsafe {
        av_register_all();
    }
    
    // 打开输入文件
    let mut format_context: *mut AVFormatContext = std::ptr::null_mut();
    let filename = std::ffi::CString::new("input.mp4").unwrap();
    
    unsafe {
        if avformat_open_input(&mut format_context, filename.as_ptr(), std::ptr::null_mut(), std::ptr::null_mut()) != 0 {
            eprintln!("无法打开输入文件");
            return;
        }
        
        // 获取流信息
        if avformat_find_stream_info(format_context, std::ptr::null_mut()) < 0 {
            eprintln!("无法获取流信息");
            return;
        }
        
        // 查找视频流
        let mut video_stream_index = -1;
        for i in 0..(*format_context).nb_streams {
            if (*(*format_context).streams.offset(i as isize)).codecpar().codec_type == AVMEDIA_TYPE_VIDEO {
                video_stream_index = i as i32;
                break;
            }
        }
        
        if video_stream_index == -1 {
            eprintln!("未找到视频流");
            return;
        }
        
        println!("成功打开文件并找到视频流");
        
        // 清理资源
        avformat_close_input(&mut format_context);
    }
}

完整示例代码:

// Cargo.toml
// [dependencies]
// ffmpeg-sys-next = "8.0.0"

use ffmpeg_sys_next::*;
use std::ffi::CString;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 初始化FFmpeg
    unsafe {
        av_register_all();
    }
    
    let filename = "input.mp4";
    let c_filename = CString::new(filename)?;
    
    // 打开媒体文件
    let mut format_ctx: *mut AVFormatContext = std::ptr::null_mut();
    unsafe {
        if avformat_open_input(&mut format_ctx, c_filename.as_ptr(), std::ptr::null_mut(), std::ptr::null_mut()) != 0 {
            return Err("无法打开输入文件".into());
        }
        
        // 获取流信息
        if avformat_find_stream_info(format_ctx, std::ptr::null_mut()) < 0 {
            avformat_close_input(&mut format_ctx);
            return Err("无法获取流信息".into());
        }
        
        // 打印媒体信息
        av_dump_format(format_ctx, 0, c_filename.as_ptr(), 0);
        
        // 查找视频流
        let video_stream_index = find_video_stream(format_ctx);
        if video_stream_index == -1 {
            avformat_close_input(&mut format_ctx);
            return Err("未找到视频流".into());
        }
        
        println!("视频流索引: {}", video_stream_index);
        
        // 清理资源
        avformat_close_input(&mut format_ctx);
    }
    
    Ok(())
}

// 查找视频流
fn find_video_stream(format_ctx: *mut AVFormatContext) -> i32 {
    unsafe {
        for i in 0..(*format_ctx).nb_streams {
            let stream = *(*format_ctx).streams.offset(i as isize);
            if (*stream).codecpar.codec_type == AVMEDIA_TYPE_VIDEO {
                return i as i32;
            }
        }
    }
    -1
}

这个示例演示了如何使用ffmpeg-sys-next打开媒体文件、获取流信息并查找视频流。请注意,使用FFmpeg需要正确处理内存管理和错误处理。


1 回复

Rust FFmpeg绑定库ffmpeg-sys-next使用指南

概述

ffmpeg-sys-next是Rust语言的FFmpeg绑定库,提供跨平台的音视频处理和多媒体编解码功能。该库为Rust开发者提供了直接访问FFmpeg底层C API的能力,支持音视频解码、编码、转码、过滤等多媒体操作。

安装配置

添加依赖

在Cargo.toml中添加:

[dependencies]
ffmpeg-sys-next = "0.5"

系统依赖

需要先安装FFmpeg开发库:

  • Ubuntu/Debian: sudo apt-get install libavcodec-dev libavformat-dev libavutil-dev
  • macOS: brew install ffmpeg
  • Windows: 下载预编译的FFmpeg开发包

基本使用方法

初始化FFmpeg

use ffmpeg_sys_next::*;

fn main() {
    unsafe {
        avformat_network_init();
    }
    println!("FFmpeg初始化成功");
}

打开媒体文件

use std::ptr;
use ffmpeg_sys_next::*;

fn open_media_file(path: &str) -> Result<(), String> {
    unsafe {
        let mut format_context: *mut AVFormatContext = ptr::null_mut();
        
        if avformat_open_input(&mut format_context, 
                             path.as_ptr() as *const i8,
                             ptr::null_mut(), 
                             ptr::null_mut()) != 0 {
            return Err("无法打开媒体文件".to_string());
        }
        
        if avformat_find_stream_info(format_context, ptr::null_mut()) < 0 {
            return Err("无法获取流信息".to_string());
        }
        
        // 处理媒体文件...
        avformat_close_input(&mut format_context);
    }
    Ok(())
}

解码视频帧示例

use ffmpeg_sys_next::*;
use std::ptr;

fn decode_video_frame() {
    unsafe {
        let codec = avcodec_find_decoder(AVCodecID::AV_CODEC_ID_H264);
        if codec.is_null() {
            panic!("找不到H264解码器");
        }
        
        let codec_context = avcodec_alloc_context3(codec);
        if codec_context.is_null() {
            panic!("无法分配编解码器上下文");
        }
        
        let packet = av_packet_alloc();
        let frame = av_frame_alloc();
        
        // 解码逻辑...
        
        av_packet_free(&mut packet);
        av_frame_free(&mut frame);
        avcodec_free_context(&mut codec_context);
    }
}

高级功能

音频重采样

use ffmpeg_sys_next::*;

fn resample_audio() {
    unsafe {
        let swr_context = swr_alloc();
        // 配置重采样参数...
        swr_init(swr_context);
        // 执行重采样操作...
        swr_free(&mut swr_context);
    }
}

视频缩放

use ffmpeg_sys_next::*;

fn scale_video() {
    unsafe {
        let sws_context = sws_getContext(
            1920, 1080, AV_PIX_FMT_YUV420P,
            1280, 720, AV_PIX_FMT_YUV420P,
            SWS_BILINEAR, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()
        );
        // 执行缩放操作...
        sws_freeContext(sws_context);
    }
}

完整示例demo

以下是一个完整的媒体文件信息读取示例:

use ffmpeg_sys_next::*;
use std::ffi::CStr;
use std::ptr;

fn main() -> Result<(), String> {
    // 初始化FFmpeg网络模块
    unsafe {
        avformat_network_init();
    }

    // 打开媒体文件
    let file_path = "test.mp4";
    let mut format_ctx: *mut AVFormatContext = ptr::null_mut();
    
    unsafe {
        // 打开输入文件
        if avformat_open_input(
            &mut format_ctx,
            file_path.as_ptr() as *const i8,
            ptr::null_mut(),
            ptr::null_mut(),
        ) != 0
        {
            return Err("无法打开媒体文件".to_string());
        }

        // 获取流信息
        if avformat_find_stream_info(format_ctx, ptr::null_mut()) < 0 {
            avformat_close_input(&mut format_ctx);
            return Err("无法获取流信息".to_string());
        }

        // 打印媒体文件信息
        println!("媒体文件信息:");
        println!("持续时间: {} 微秒", (*format_ctx).duration);
        println!("比特率: {} bps", (*format_ctx).bit_rate);
        println!("流数量: {}", (*format_ctx).nb_streams);

        // 遍历所有流
        for i in 0..(*format_ctx).nb_streams {
            let stream = *(*format_ctx).streams.offset(i as isize);
            let codec_type = (*stream).codecpar.as_ref().unwrap().codec_type;

            match codec_type {
                AVMediaType::AVMEDIA_TYPE_VIDEO => {
                    println!("流 {}: 视频流", i);
                    let codecpar = (*stream).codecpar.as_ref().unwrap();
                    println!("  编码格式: {:?}", codecpar.codec_id);
                    println!("  分辨率: {}x{}", codecpar.width, codecpar.height);
                }
                AVMediaType::AVMEDIA_TYPE_AUDIO => {
                    println!("流 {}: 音频流", i);
                    let codecpar = (*stream).codecpar.as_ref().unwrap();
                    println!("  编码格式: {:?}", codecpar.codec_id);
                    println!("  采样率: {}", codecpar.sample_rate);
                    println!("  声道数: {}", codecpar.channels);
                }
                _ => println!("流 {}: 其他类型流", i),
            }
        }

        // 清理资源
        avformat_close_input(&mut format_ctx);
    }

    println!("媒体文件处理完成");
    Ok(())
}

注意事项

  1. 内存安全: 由于直接调用C库,需要特别注意内存管理和空指针检查
  2. 错误处理: 所有FFmpeg函数都应检查返回值
  3. 线程安全: FFmpeg某些函数不是线程安全的,需要注意同步
  4. 资源释放: 确保正确释放所有分配的资源

跨平台支持

ffmpeg-sys-next支持Windows、Linux、macOS等主流平台,但需要确保目标系统已安装相应版本的FFmpeg开发库。

这个绑定库为Rust开发者提供了强大的多媒体处理能力,适合开发音视频处理工具、媒体服务器、转码工具等应用。

回到顶部