🍣

Rustでffmpegを使って動画の情報を得る

に公開

目的

動画の再生時間やら諸々の情報を知りたいです。Rustでffmpegを使って調べてみます。

ffmpegのインストール

Ubuntu24.04にffmpegをインストールします。現在最新の8.0をインストールしたいので以下のサイトを参考に入れてみます。

Install FFmpeg (8.0 Updated) via PPA in Ubuntu 22.04 | Ubuntu 24.04

sudo add-apt-repository ppa:ubuntuhandbook1/ffmpeg8
sudo apt update
sudo apt install libavutil-dev libavformat-dev libavfilter-dev libavcodec-dev ffmpeg

ffmpeg以外はビルドした時に要求されたので追加しています。

コード

Cargo.toml
[package]
name = "samples"
version = "0.1.0"
edition = "2024"

[dependencies]
ffmpeg-next = "8.0.0"
main.rs
use ffmpeg_next::format;

fn main() {
    let format_context = format::input("samples/sample.mp4").unwrap();

    println!("BitRate: {}", format_context.bit_rate());
    println!("Number of chapters: {}", format_context.chapters().len());
    println!("Number of streams: {}", format_context.streams().len());

    let duration = format_context.duration();
    println!("Duration: {} microseconds", duration);

    let format = format_context.format();
    println!("Format name: {}", format.name());
    println!("Format description: {}", format.description());
    println!("Format extentions: {:?}", format.extensions());
    println!("Format mime types: {:?}", format.mime_types());

    let metadata = format_context.metadata();
    for (key, value) in metadata.iter() {
        println!("Metadata: {}: {}", key, value);
    }

    for stream in format_context.streams() {
        println!("Stream {}:", stream.index());
        println!("  Time Base: {}/{}", stream.time_base().numerator(), stream.time_base().denominator());
        println!("  Duration: {}", stream.duration());
        println!("  Frames: {}", stream.frames());
        println!("  Rate: {}", stream.rate());
        println!("  Disposition: {:?}", stream.disposition());
        println!("  Avg Frame Rate: {:?}", stream.avg_frame_rate());
        println!("  Start Time: {}", stream.start_time());
        println!("  Discard: {:?}", stream.discard());

        for (key, value) in stream.metadata().iter() {
            println!("  Metadata: {}: {}", key, value);
        }

        let parameters = stream.parameters();
        println!("  Codec ID Name: {}", parameters.id().name());
        println!("  Codec Type: {:?}", parameters.medium());
        let width = unsafe { parameters.as_ptr().as_ref().and_then(|p| Some(p.width)).unwrap_or(0) };
        println!("  Width: {}", width);
        let height = unsafe { parameters.as_ptr().as_ref().and_then(|p| Some(p.height)).unwrap_or(0) };
        println!("  Height: {}", height);
        let bit_rate = unsafe { parameters.as_ptr().as_ref().and_then(|p| Some(p.bit_rate)).unwrap_or(0) };
        println!("  Bit Rate: {}", bit_rate);
        let pixel_format = unsafe { parameters.as_ptr().as_ref().and_then(|p| Some(p.format)).unwrap_or(-1) };
        println!("  Pixel Format: {}", pixel_format);

        

        let side_data_iter = stream.side_data();
        for side_data in side_data_iter {
            println!("  Side Data Type: {:?}", side_data.kind());
        }
    };
}
結果
BitRate: 20211358
Number of chapters: 0
Number of streams: 3
Duration: 5366833 microseconds
Format name: mov,mp4,m4a,3gp,3g2,mj2
Format description: QuickTime / MOV
Format extentions: ["mov", "mp4", "m4a", "3gp", "3g2", "mj2", "psp", "m4b", "ism", "ismv", "isma", "f4v", "avif", "heic", "heif"]
Format mime types: []
Metadata: major_brand: isom
Metadata: minor_version: 131072
Metadata: compatible_brands: isomiso2mp41
Metadata: creation_time: 2025-11-25T22:41:36.000000Z
Metadata: location: +35.6878+139.7033/
Metadata: location-eng: +35.6878+139.7033/
Metadata: com.android.capture.fps: 30.000000
Metadata: com.android.model: Pixel 8
Metadata: com.android.manufacturer: Google
Stream 0:
  Time Base: 1/90000
  Duration: 483015
  Frames: 161
  Rate: 30/1
  Disposition: Disposition(DEFAULT)
  Avg Frame Rate: Rational(966000/32201)
  Start Time: 0
  Discard: Default
  Metadata: creation_time: 2025-11-25T22:41:36.000000Z
  Metadata: language: eng
  Metadata: handler_name: VideoHandle
  Metadata: vendor_id: [0][0][0][0]
  Codec ID Name: hevc
  Codec Type: Video
  Width: 1920
  Height: 1080
  Bit Rate: 19953549
  Pixel Format: 12
  Side Data Type: DisplayMatrix
Stream 1:
  Time Base: 1/48000
  Duration: 256084
  Frames: 250
  Rate: 0/0
  Disposition: Disposition(DEFAULT)
  Avg Frame Rate: Rational(0/0)
  Start Time: 878
  Discard: Default
  Metadata: creation_time: 2025-11-25T22:41:36.000000Z
  Metadata: language: eng
  Metadata: handler_name: SoundHandle
  Metadata: vendor_id: [0][0][0][0]
  Codec ID Name: aac
  Codec Type: Audio
  Width: 0
  Height: 0
  Bit Rate: 192184
  Pixel Format: 8
Stream 2:
  Time Base: 1/90000
  Duration: 483015
  Frames: 161
  Rate: 0/0
  Disposition: Disposition(DEFAULT)
  Avg Frame Rate: Rational(0/0)
  Start Time: 0
  Discard: Default
  Metadata: creation_time: 2025-11-25T22:41:36.000000Z
  Metadata: language: eng
  Metadata: handler_name: MetaHandle
  Codec ID Name: none
  Codec Type: Data
  Width: 0
  Height: 0
  Bit Rate: 50162
  Pixel Format: -1

まとめ

正直データが生すぎて使いにくいですね。unsafeなんていちいち書かなくて済むようなstructを作って欲しいです。
ffmpeg-nextをラップしたライブラリはいくつかあるんですが、8.0に対応してくれて無いので待ってます。

Discussion