rsmpeg is a thin&safe layer above the FFmpeg's Rust bindings

Related tags

Video rsmpeg
Overview

Rsmpeg

Doc Crates.io CI

rsmpeg is a thin&safe layer above the FFmpeg's Rust bindings, it's main goal is safely exposing FFmpeg inner APIs in Rust as much as possible.

Taking advantage of Rust's language design, you can build robust multi-media projects even quicker than using FFmpeg's C API.

Getting started

FFmpeg compilation

To use your first rsmpeg demo, you need to compile your FFmpeg:

  1. https://github.com/ffmpeg/ffmpeg.
  2. https://trac.ffmpeg.org/wiki/CompilationGuide

If you find the compilation compilcated, there are some helpful compiling scripts for you (under the utils folder).

To build a FFmpeg with some common parameters: (don't forget to install the build dependencies)

# macOS
zsh utils/mac_ffmpeg.rs
# Linux
bash utils/linux_ffmpeg.rs
# Windows
# You need a Linux machine for cross compiling, then copy the artifact to your
# Windows machine.
bash utils/windows_ffmpeg.rs

Rsmpeg demo

Ensure that you have compiled the FFmpeg.

Start by adding rsmpeg to your Cargo.toml file:

[dependencies]
rsmpeg = "0.3.0"

Write your simple media file info dumper:

use std::ffi::{CStr, CString};
use std::error::Error;
use rsmpeg::avformat::AVFormatContextInput;

fn dump_av_info(path: &CStr) -> Result<(), Box<dyn Error>> {
    let mut input_format_context = AVFormatContextInput::open(path)?;
    input_format_context.dump(0, path)?;
    Ok(())
}

fn main() {
    dump_av_info(&CString::new("./test.jpg").unwrap()).unwrap();
}

Prepare a simple image in your current folder:

test.jpg

Run with FFMPEG_PKG_CONFIG_PATH set to the pkgconfig file path in your artifact folder (xxx/ffmpeg_build/lib/pkgconfig).

# macOS & Linux
export FFMPEG_PKG_CONFIG_PATH=xxx/ffmpeg_build/lib/pkgconfig
# Windows
set FFMPEG_PKG_CONFIG_PATH=xxx/ffmpeg_build/lib/pkgconfig

cargo run

Then it works:

Input #0, image2, from './test.jpg':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 1390 kb/s
  Stream #0:0: Video: mjpeg, none, 25 fps, 25 tbr, 25 tbn, 25 tbc

(A single image's duration under 25fps is 0.04s)

You can also put any video or audio file here, this program will dump the media info for you.

Advanced usage

  1. FFmpeg linking: refer to rusty_ffmpeg's documentation for how to use environment variables to statically or dynamically link FFmpeg.

  2. Advanced usage of rsmpeg: Check out the tests and examples folder.

Dependency version

Supported FFmpeg version is 4.0-4.4.

Minimum Supported Rust Version is 1.52(Stable channel).

Comments
  • 希望改进 AVFormatContextOutput::create 函数, 可以轻松实现 output format 的 custom io

    希望改进 AVFormatContextOutput::create 函数, 可以轻松实现 output format 的 custom io

    现在接口还不是很完善, 由于我需要 output format 的 custom io, 需要实现: 不输出到文件(即文件名是null), 指定format 比如为mp4, 我需要用 custom io, 在输出format时, 拿到输出的所有数据做别的处理. 现在我的做法是修改了rsmpeg源码, 可以满足我的需求, 但是希望源码可以直接可以满足需求: image

    我的用法: image image

    非常感谢这个库, 整体还是很好用~

    opened by imxood 15
  • 重新封装,不做解编码

    重新封装,不做解编码

    想用rsmpeg 实现下面的功能,因为ffmpeg 是lgpl 协议所有没有libx264 依赖。 ./ffmpeg -r 30 -i xxxx.h264 -c:v copy -f mp4 xxxxx.mp4

    基于tests/avio_writing.rs 删除了decode 和encode 部分, 但是无法通过 AVframe去设置 pts 时间,导致程序报错,请给一些建议。 image

    图片来自此连接-章节2-重新封装

    opened by sunxingsong 8
  • How do I associate multiple inputs in the filter

    How do I associate multiple inputs in the filter

    I want to achieve split screen effect, at the beginning, I will associate multiple inputs in the filter. but I can't do it, because of the wrong

    outputs.next = video1_outputs.as_mut_ptr();
    
    cannot assign to data in a dereference of `rsmpeg::avfilter::AVFilterInOut`
    trait `DerefMut` is required to modify through a dereference, but it is not implemented for `rsmpeg::avfilter::AVFilterInOut`
    

    the main code:

    // 创建buffer, 用于接收输入
    let buffer_src = AVFilter::get_by_name(cstr!("buffer")).unwrap();
    
    // video0: 创建 filter 上下文, 关联 输入的 buffer
    let mut buffer_src_context =
      filter_graph.create_filter_context(&buffer_src, cstr!("video0"), Some(args))?;
    // video0: 分配 filter 的输入, 关联 创建的 filter 上下文
    let mut outputs = AVFilterInOut::new(cstr!("video0"), &mut buffer_src_context, 0);
    
    // video1: 创建 filter 上下文, 关联 输入的 buffer
    let mut buffer_src_context =
      filter_graph.create_filter_context(&buffer_src, cstr!("video1"), Some(args))?;
    // video1: 分配 filter 的输入, 关联 创建的 filter 上下文
    let mut video1_outputs = AVFilterInOut::new(cstr!("video1"), &mut buffer_src_context, 0);
    
    // 关联 多个输入
    outputs.next = video1_outputs.as_mut_ptr();
    // outputs.next = video1_outputs.into_raw().as_ptr();
    

    in rsmpeg: wrap!(AVFilterInOut: ffi::AVFilterInOut); this is: wrap_pure!(($name): $ffi_type $(,$attach: $attach_type = $attach_default)*); and this implements

    pub fn as_mut_ptr(&mut self) -> *mut $ffi_type {
       self.something_should_not_be_touched_directly.as_ptr()
    }
    

    but why can't it --> outputs.next = video1_outputs.as_mut_ptr();

    opened by imxood 8
  • 某个 mp4 生成缩略图失败

    某个 mp4 生成缩略图失败

    video.mp4

    下载这个 mp4,替换 tests/assets/vids/bear.mp4,然后执行 thumbnail 测试:

    wget https://user-images.githubusercontent.com/1524609/131678290-c6b90aee-d018-4078-99b4-45cc410bd67b.mp4 -O video.mp4
    cp video.mp4 tests/assets/vids/bear.mp4
    cargo test --test thumbnail
    

    会得到如下错误:

        Finished test [unoptimized + debuginfo] target(s) in 0.04s
         Running tests/thumbnail.rs (target/debug/deps/thumbnail-fb8cd98fade3377b)
    
    running 1 test
    test thumbnail_test ... FAILED
    
    failures:
    
    ---- thumbnail_test stdout ----
    thread 'thumbnail_test' panicked at 'called `Result::unwrap()` on an `Err` value: Cannnot find video cover packet', tests/thumbnail.rs:132:6
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    
    failures:
        thumbnail_test
    
    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
    error: test failed, to rerun pass '--test thumbnail'
    
    opened by nanpuyue 6
  • way to get AVPixFmtDescriptor from a format number

    way to get AVPixFmtDescriptor from a format number

    For proper video rendering, we need to know the stride, but that involves having info about the pixel format, which is stored into

    https://docs.rs/rsmpeg/0.8.0/rsmpeg/ffi/struct.AVPixFmtDescriptor.html

    is there a way to get this information in rsmpeg given a frame.format number?

    opened by lattice0 5
  • Compilation error

    Compilation error

    Hello,

    The last version of rsmpeg (0.6.0) doesn't seem to compile:

    
    error[E0425]: cannot find function `av_gcd_q` in module `ffi`
        --> /home/lorenzo/.cargo/registry/src/github.com-1ecc6299db9ec823/rsmpeg-0.6.0/src/avutil/rational.rs:65:19
         |
    65   |     unsafe { ffi::av_gcd_q(a, b, max_den, def) }
         |                   ^^^^^^^^
         |
        ::: /home/lorenzo/Scrivania/Varie/repo/remotia/target/debug/build/rusty_ffmpeg-f322e92cb20dcce1/out/binding.rs:6392:5
         |
    6392 |     pub fn av_add_q(b: AVRational, c: AVRational) -> AVRational;
         |     ------------------------------------------------------------ similarly named function `av_add_q` defined here
         |
    help: a function with a similar name exists
         |
    65   |     unsafe { ffi::av_add_q(a, b, max_den, def) }
         |                   ~~~~~~~~
    help: consider importing this function
         |
    1    | use crate::avutil::av_gcd_q;error[E0425]: cannot find function `av_gcd_q` in module `ffi`
        --> /home/lorenzo/.cargo/registry/src/github.com-1ecc6299db9ec823/rsmpeg-0.6.0/src/avutil/rational.rs:65:19
         |
    65   |     unsafe { ffi::av_gcd_q(a, b, max_den, def) }
         |                   ^^^^^^^^
         |
        ::: /home/lorenzo/Scrivania/Varie/repo/remotia/target/debug/build/rusty_ffmpeg-f322e92cb20dcce1/out/binding.rs:6392:5
         |
    6392 |     pub fn av_add_q(b: AVRational, c: AVRational) -> AVRational;
         |     ------------------------------------------------------------ similarly named function `av_add_q` defined here
         |
    help: a function with a similar name exists
         |
    65   |     unsafe { ffi::av_add_q(a, b, max_den, def) }
         |                   ~~~~~~~~
    help: consider importing this function
         |
    1    | use crate::avutil::av_gcd_q;
         |
         |
    

    I've tried downgrading the ffmpeg release to 4.3 but it doesn't seem to work.

    rustc --version output is:

    rustc 1.56.1 (59eed8a2a 2021-11-01)

    opened by aegroto 5
  • AVBitStreamFilter

    AVBitStreamFilter

    I'm trying to implement AVBitStreamFilter in this library. I have a little code so far but I'm not sure if I'm working in the right direction. AVBitStreamFilter was easy but AVBSFContext has a bit of a strange allocation method and I couldn't find another example like it in your code.

    Would you mind taking a look and letting me know if I'm doing anything wrong? This is what I have so far.

    use std::{ffi::CStr, mem::MaybeUninit, ptr::NonNull};
    
    use crate::{
        error::{Result, RsmpegError},
        ffi,
        shared::PointerUpgrade,
    };
    
    wrap!(AVBitStreamFilter: ffi::AVBitStreamFilter);
    
    impl AVBitStreamFilter {
        /// Find a bitstream filter instance with it's short name.
        pub fn find_decoder_by_name(name: &CStr) -> Option<AVBitStreamFilter> {
            unsafe { ffi::av_bsf_get_by_name(name.as_ptr()) }
                .upgrade()
                .map(|x| unsafe { AVBitStreamFilter::from_raw(x) })
        }
    }
    
    wrap!(AVBSFContext: ffi::AVBSFContext);
    
    impl AVBSFContext {
        /// Create a new [`AVBSFContext`] instance, allocate private data and
        /// initialize defaults for the given [`AVBitStreamFilter`].
        pub fn new(filter: &AVBitStreamFilter) -> Result<Self> {
            let mut bsfc_raw: MaybeUninit<ffi::AVBSFContext> = MaybeUninit::uninit();
    
            match unsafe { ffi::av_bsf_alloc(filter.as_ptr(), &mut bsfc_raw.as_mut_ptr()) } {
                0 => {
                    let bsfc = unsafe {
                        AVBSFContext::from_raw(NonNull::new(&mut bsfc_raw.assume_init()).unwrap())
                    };
                    Ok(bsfc)
                }
                e => Err(RsmpegError::AVError(e)),
            }
        }
    }
    
    
    opened by FallingSnow 5
  • Better avformat pointer wrapping

    Better avformat pointer wrapping

    pub fn iformat(&'stream self) -> AVInputFormatRef<'stream> {
        unsafe { AVInputFormatRef::from_raw(NonNull::new(self.iformat).unwrap()) }
    }
    

    As the above example code, self.iformat maybe a null pointer cause panic at runtime, consider a new approach:

    pub fn iformat(&'stream self) -> Option<AVInputFormatRef<'stream>> {
        unsafe { NonNull::new(self.iformat).map(AVInputFormatRef::from_raw) }
    }
    
    opened by Jamyw7g 4
  • mutable `data_mut` and `linesize_mut`

    mutable `data_mut` and `linesize_mut`

    at https://github.com/larksuite/rsmpeg/blob/master/src/avutil/frame.rs#L76, these two

        pub fn data_mut(&mut self) -> &mut [*mut u8; 8] {
            unsafe { &mut self.deref_mut().data }
        }
    
        pub fn linesize_mut(&mut self) -> &mut [libc::c_int; 8] {
            unsafe { &mut self.deref_mut().linesize }
        }
    

    are mutable. Can I do versions for &self? Also, why it returns &mut [*mut u8; 8] and not &mut [&mut[u8]]? I have to rely on usafe outside of the library to do std::slice::from_raw_parts (is it even safe?)

    opened by lattice0 3
  • WIP: Feature/avbsf

    WIP: Feature/avbsf

    No really sure how to do error handling for send and receive packet. I know the FFI functions return i32 but I'm not sure how to make that a useful error in rsmpeg other than AVError(i32).

    opened by FallingSnow 3
  • 请问怎么才能生成Fragmented MP4

    请问怎么才能生成Fragmented MP4

    想生成FMP4 方便在游览器上观看: 实现类似的效果: ffmpeg.exe -i test.264 -f mp4 -movflags frag_keyframe+empty_moov output.mp4 我看其他教程,用C语言时候,写入文件格式头信息的时候设置AVDictionary结构体

    AVDictionary *opts = NULL;
    av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
    avformat_write_header(o_fmt_ctx, &opts);
    av_dict_free(&opts);
    

    但是,我看了源码rsmpeg的话默认设置null

    pub fn write_header(&mut self) -> Result<()> {
            unsafe { ffi::avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) }
                .upgrade()
                .map_err(RsmpegError::WriteHeaderError)?;
    
            Ok(())
        }
    

    我对ffmpeg不是很了解,是不是还有其他方法呢?请教一下。

    opened by lyaf 2
Owner
Lark Technologies Pte. Ltd.
Lark Technologies Pte. Ltd.
Rust high level RTSP client

RRTSP Client Currently works, but a lot of work to do. PRs welcome! Examples, crates.io, better Readme.md and other things coming soon.

Lucas Zanela 13 Dec 26, 2022
High-level RTSP multimedia streaming library, in Rust

High-level RTSP multimedia streaming library, in Rust. Good support for ONVIF RTSP/1.0 IP surveillance cameras, as needed by Moonfire NVR. Works around brokenness in cheap closed-source cameras.

Scott Lamb 108 Jan 8, 2023
Rust-based video player for astrophotography

Astro Video Player Rust-based video player for astrophotography videos in SER and AVI format. Supports debayering of RAW color images. Status: Works w

Andy Grove 6 May 7, 2022
Pure-rust implementation of legacy H.263 video codec and associated color transforms

website | demo | nightly builds | wiki h263-rs h263-rs is a pure-Rust implementation of ITU-T Recommendation H.263 (2005/08), a video codec commonly u

Ruffle 7 Dec 18, 2022
A ffmpeg/rust based HLS stream generator

hls-streamer Stream your heart's content with HLS. Movtivation I've got a CCTV camera from AliExpress, I know I can use ffmpeg hls demuxer to split up

null 16 Jan 9, 2023
A not well-named youtube's videos downloader written in Rust 🦀

ytdl-rs A not well-named youtube's videos downloader written in Rust ?? For information about how to use, legal section, next steps in the project, co

Alejandro Lopez 6 Jun 17, 2022
Yet another video to ASCII animation (in Rust)

Yet another video to ASCII tool (in Rust) Requirements opencv Installation cargo install video2ascii You may also want to add

jwnhy 42 Dec 28, 2022
Xiu - A simple and secure live media server in pure Rust (RTMP/HTTP-FLV/HLS/Relay).🦀

Xiu is a simple and secure live media server written by pure Rust, it now supports popular live protocols like RTMP/HLS/HTTP-FLV (and maybe other protocols in the future), you can deploy it as a stand-alone server or a cluster using the relay feature.

HarlanC 602 Jan 2, 2023
Media Cleaner is a simple CLI tool to clean up your media library based on your Overseerr requests and Tautulli history, written in Rust.

Media Cleaner Media Cleaner is a simple CLI tool to clean up your media library based on your Overseerr requests and Tautulli history, written in Rust

Felix Bjerhem Aronsson 21 Mar 22, 2023
Aggressively reliable delivery layer. Above UDP. Nothing else.

Aggressively reliable delivery layer. Above UDP. Nothing else.

IchHabeKeineNamen 2 Jun 5, 2022
The classic game Pong, written in lambda calculus, and a thin layer of Rust.

What? The good old game Pong, written in lambda calculus, and a thin layer of Rust. Why? I was bored. No, seriously, why? Everyone keeps saying that l

null 2 Aug 14, 2022
Thin but safe ALSA wrappers for Rust

ALSA bindings for Rust Thin but safe wrappers for ALSA, the most common API for accessing audio devices on Linux. The ALSA API is rather big, so every

null 91 Dec 26, 2022
Unsafe bindings and a safe wrapper for gtk4-layer-shell, automatically generated from a .gir file

gtk4-layer-shell: gtk4-layer-shell-sys: gtk4-layer-shell This is the safe wrapper for gtk4-layer-shell, automatically generated from its .gir file. Fo

null 3 Apr 30, 2023
Transforms UDP stream into (fake) TCP streams that can go through Layer 3 & Layer 4 (NAPT) firewalls/NATs.

Phantun A lightweight and fast UDP to TCP obfuscator. Table of Contents Phantun Latest release Overview Usage 1. Enable Kernel IP forwarding 2. Add re

Datong Sun 782 Dec 30, 2022
Command-Line program that takes images and produces the copy of the image with a thin frame and palette made of the 10 most frequent colors.

paleatra v.0.0.1 Command-Line program that takes an image and produces the copy of the image with a thin frame and palette made of the 10 most frequen

Beka Modebadze 24 Dec 29, 2022
Thin wrapper around starship.rs to format kakoune status line

kakship is just a thin wrapper around starship to format the status line of kakoune and is meant to be used with the included kakoune script kakship.kak.

Eric Burghard 15 Jun 7, 2022
A thin-hypervisor that runs on aarch64 CPUs.

How to build the hypervisor By Rust toolchain (TBD) By docker Requirements Docker (Tested by Docker version 20.10.8, build 3967b7d28e) I tested by non

RIKEN R-CCS 54 Dec 12, 2022
Brotlic (or BrotliC) is a thin wrapper around brotli.

Bindings to the brotli library featuring a low-overhead encoder and decoder, Writers and Readers for compression and decompression at customizable compression qualities and window sizes.

Aron Parker 18 Dec 9, 2022
Thin wrapper around [`tokio::process`] to make it streamable

process-stream Wraps tokio::process::Command to future::stream. Install process-stream = "0.2.2" Example usage: From Vec<String> or Vec<&str> use proc

null 4 Jun 25, 2022
Thin wrapper around [`tokio::process`] to make it streamable

This library provide ProcessExt to create your own custom process

null 4 Jun 25, 2022