<h1 align="center">
Ffmpegx
</h1>
<h4 align="center">
Rust bindings for FFmpeg, providing common features such as frame sequence decoding and PCM data encoding/decoding.
</h4>
<p align="center">
<a href="https://github.com/0xhappyboy/ffmpegx/LICENSE"><img src="https://img.shields.io/badge/Apache2.0-d1d1f6.svg?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=googledocs&label=license&logoColor=BEC5C9" alt="License"></a>
</p>
<p align="center">
<a href="./README_zh-CN.md">简体中文</a> | <a href="./README.md">English</a>
</p>
## Examples
### Get Video Metadata and Generate Thumbnail
```rust
use ffmpegx::{Ffmpeg, ThumbnailOptions};
fn process_video(video_path: &str) -> Result<(), String> {
// Create Ffmpeg instance (automatically detects ffmpeg path)
let ffmpeg = Ffmpeg::new();
// Get video metadata
let metadata = ffmpeg.get_video_metadata(video_path)?;
println!("Video Information:");
println!(" Duration: {:.2}s", metadata.duration);
println!(" Resolution: {}x{}", metadata.width, metadata.height);
println!(" FPS: {:.2}", metadata.fps);
println!(" Codec: {}", metadata.codec);
println!(" Has Audio: {}", metadata.has_audio);
// Generate thumbnail at 10% of video duration
let thumb_options = ThumbnailOptions {
time: metadata.duration \* 0.1,
width: Some(640),
height: Some(360),
output_path: Some("thumbnail.jpg".to_string()),
};
let thumb_path = ffmpeg.generate_thumbnail(video_path, &thumb_options)?;
println!("Thumbnail saved: {}", thumb_path);
Ok(())
}
```
### Extract Frame Sequence from Video
```rust
use ffmpegx::{Ffmpeg, DecodeVideoOptions};
use std::path::Path;
fn extract_video_frames(video_path: &str, output_dir: &str) -> Result<Vec<String>, String> {
let ffmpeg = Ffmpeg::new();
let frames_dir = Path::new(output_dir).join("frames");
let audio_path = Path::new(output_dir).join("audio.wav");
let options = DecodeVideoOptions {
fps: 30.0,
duration: 10.0,
width: 1280.0,
height: 720.0,
quality: 8,
extract_audio: true,
start_time: None,
};
ffmpeg.decode_video(video_path, &frames_dir, &audio_path, &options)?;
let (frame_count, frame_paths) = ffmpeg.get_frame_sequence_info(&frames_dir)?;
println!("Extracted {} frames", frame_count);
Ok(frame_paths)
}
```
### Extract PCM Audio Data and Generate Waveform
```rust
use ffmpegx::{
extract_audio_pcm_data_from_path,
generate_waveform_image,
Ffmpeg,
};
use std::path::Path;
fn process_audio(audio_path: &str) -> Result<Vec<f32>, String> {
// Extract PCM samples from audio
let pcm_samples = extract_audio_pcm_data_from_path(
Path::new(audio_path),
0.0, // start_time
30.0, // duration
)?;
println!("PCM Samples extracted: {}", pcm_samples.len());
// Analyze audio
if !pcm_samples.is_empty() {
let max_peak = pcm_samples.iter()
println!("Max Peak: {:.4}", max_peak);
}
// Generate waveform image
let ffmpeg = Ffmpeg::new();
generate_waveform_image(
&ffmpeg,
audio_path,
Path::new("waveform.png"),
1200,
200,
"#2d8a6e",
)?;
Ok(pcm_samples)
}
```
### Full Video Processing Pipeline
```rust
use ffmpegx::{
extract_audio_pcm_data_from_path,
generate_waveform_image,
Ffmpeg,
ThumbnailOptions,
DecodeVideoOptions,
};
use std::path::Path;
fn process_video_complete(video_path: &str) -> Result<(), String> {
let ffmpeg = Ffmpeg::new();
println!("FFmpeg path: {}", ffmpeg.bin_path);
// Get metadata
let metadata = ffmpeg.get_video_metadata(video_path)?;
println!("\n=== Video Metadata ===");
println!("Duration: {:.2}s", metadata.duration);
println!("Resolution: {}x{}", metadata.width, metadata.height);
println!("FPS: {}", metadata.fps);
// Generate thumbnail
let thumb_options = ThumbnailOptions {
time: 5.0,
width: Some(640),
height: Some(360),
output_path: Some("thumbnail.jpg".to_string()),
};
ffmpeg.generate_thumbnail(video_path, &thumb_options)?;
// Extract audio PCM data
let pcm_data = extract_audio_pcm_data_from_path(
Path::new(video_path),
0.0,
10.0,
)?;
if !pcm_data.is_empty() {
let avg = pcm_data.iter().map(|&s| s.abs()).sum::<f32>() / pcm_data.len() as f32;
let max = pcm_data.iter().map(|&s| s.abs()).fold(0.0, f32::max);
println!("\n=== Audio Analysis ===");
println!("Samples: {}", pcm_data.len());
println!("Average amplitude: {:.4}", avg);
println!("Peak amplitude: {:.4}", max);
}
// Generate waveform
generate_waveform_image(&ffmpeg, video_path, Path::new("waveform.png"), 1200, 300, "#00ff00")?;
Ok(())
}
```
### Encode Frame Sequence to Video
```rust
use ffmpegx::{Ffmpeg, FrameSequence, VideoEncodeOptions, VideoCodec, EncoderPreset, HwAccel};
use std::path::Path;
fn encode_video_from_frames(frames_dir: &str, output_path: &str) -> Result<(), String> {
let ffmpeg = Ffmpeg::new();
let frame_sequence = FrameSequence::from_dir(Path::new(frames_dir))?;
println!("Loaded {} frames", frame_sequence.frame_count);
let video_options = VideoEncodeOptions {
width: 1920,
height: 1080,
fps: 30.0,
codec: VideoCodec::H264,
bit_rate: 5_000_000,
crf: 23,
preset: EncoderPreset::Medium,
hwaccel: HwAccel::None,
pixel_format: "yuv420p".to_string(),
extra_args: Vec::new(),
};
ffmpeg.encode_frames_to_video(
&frame_sequence,
Path::new(output_path),
&video_options,
)?;
println!("Video saved to: {}", output_path);
Ok(())
}
```
### Encode Frame Sequence to Animated GIF
```rust
use ffmpegx::{Ffmpeg, FrameSequence, GifEncodeOptions};
use std::path::Path;
fn encode_gif_from_frames(frames_dir: &str, output_path: &str) -> Result<(), String> {
let ffmpeg = Ffmpeg::new();
let frame_sequence = FrameSequence::from_dir(Path::new(frames_dir))?;
println!("Loaded {} frames", frame_sequence.frame_count);
let gif_options = GifEncodeOptions {
width: 854,
height: 480,
fps: 24.0,
quality: "standard".to_string(),
dither: true,
loop_animation: true,
max_colors: 256,
};
ffmpeg.encode_frames_to_gif(
&frame_sequence,
Path::new(output_path),
&gif_options,
)?;
println!("GIF saved to: {}", output_path);
Ok(())
}
```
### Merge PCM Audio Directly into Video
```rust
use ffmpegx::Ffmpeg;
use std::path::Path;
fn merge_audio_into_video(video_path: &str, pcm_path: &str, output_path: &str) -> Result<(), String> {
let ffmpeg = Ffmpeg::new();
ffmpeg.merge_pcm_into_video(
Path::new(video_path),
Path::new(pcm_path),
Path::new(output_path),
"aac", // Audio format: aac, mp3, flac, wav, opus
44100, // Sample rate in Hz
2, // Channels (1=mono, 2=stereo)
192000, // Bitrate in bits per second
)?;
println!("Merged video saved to: {}", output_path);
Ok(())
}
```