ffmpegx 0.2.1

Rust bindings for FFmpeg, providing common features such as frame sequence decoding and PCM data encoding/decoding.
Documentation
<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()
.map(|&s| s.abs())
.fold(0.0_f32, |a, b| a.max(b));

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(())
}
```