vidformer/
util.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use num_rational::Rational64;
use rusty_ffmpeg::ffi;
use std::ffi::CStr;
use std::ffi::CString;

pub(crate) fn avrat_to_rat(avr: &ffi::AVRational) -> Rational64 {
    Rational64::new(avr.num as i64, avr.den as i64)
}

pub(crate) fn rat_to_avrat(rat: &Rational64) -> ffi::AVRational {
    ffi::AVRational {
        num: *rat.numer() as i32,
        den: *rat.denom() as i32,
    }
}

pub fn rand_uuid() -> String {
    uuid::Uuid::new_v4().to_string()
}

/// Instantiate FFmpeg logging
pub fn init() {
    unsafe {
        // TODO: Should be WARNING, but it keeps throwing sws warnings
        ffi::av_log_set_level(ffi::AV_LOG_ERROR as i32);
    }
}

#[derive(Debug)]
pub struct CodecDescriptor {
    pub name: String,
    pub long_name: String,
    pub format_id_pretty_name: String,
    pub has_decoder: bool,
    pub has_encoder: bool,
}

/// List all available codecs
pub fn codecs() -> Vec<CodecDescriptor> {
    let mut out = Vec::new();
    unsafe {
        let mut codec: *const ffi::AVCodecDescriptor = std::ptr::null();
        while {
            codec = ffi::avcodec_descriptor_next(codec);
            !codec.is_null()
        } {
            let codec = &*codec;
            if codec.type_ != ffi::AVMediaType_AVMEDIA_TYPE_VIDEO {
                continue;
            }

            let name = CString::new(CStr::from_ptr(codec.name).to_bytes()).unwrap();
            let long_name = CString::new(CStr::from_ptr(codec.long_name).to_bytes()).unwrap();
            let id = codec.id;
            let format_id_pretty_name = ffi::avcodec_get_name(id);
            let format_id_pretty_name =
                CString::new(CStr::from_ptr(format_id_pretty_name).to_bytes()).unwrap();

            let has_decoder = !ffi::avcodec_find_decoder(id).is_null();
            let has_encoder = !ffi::avcodec_find_encoder(id).is_null();

            out.push(CodecDescriptor {
                name: name.to_str().unwrap().to_string(),
                long_name: long_name.to_str().unwrap().to_string(),
                format_id_pretty_name: format_id_pretty_name.to_str().unwrap().to_string(),
                has_decoder,
                has_encoder,
            });
        }
    }

    out
}

pub(crate) fn fmt_av_codec(format: &ffi::AVCodec) -> String {
    let name = CString::new(unsafe { CStr::from_ptr(format.name) }.to_bytes()).unwrap();
    let long_name = CString::new(unsafe { CStr::from_ptr(format.long_name) }.to_bytes()).unwrap();
    let id = format.id;
    let format_id_pretty_name = unsafe {
        let format_id_pretty_name = ffi::avcodec_get_name(id);
        CString::new(CStr::from_ptr(format_id_pretty_name).to_bytes()).unwrap()
    };
    format!(
        "{}/{}/{}",
        name.to_str().unwrap(),
        long_name.to_str().unwrap(),
        format_id_pretty_name.to_str().unwrap()
    )
}

pub(crate) fn pixel_fmt_str_to_av_pix_fmt(s: &str) -> Result<ffi::AVPixelFormat, String> {
    let s = CString::new(s).unwrap();
    let fmt = unsafe { ffi::av_get_pix_fmt(s.as_ptr()) };
    if fmt == ffi::AVPixelFormat_AV_PIX_FMT_NONE {
        Err(format!("Invalid pixel format: {}", s.to_str().unwrap()))
    } else {
        Ok(fmt)
    }
}

pub(crate) fn pixel_fmt_str(n: i32) -> &'static str {
    unsafe {
        let fmt = ffi::av_get_pix_fmt_name(n);
        CStr::from_ptr(fmt).to_str().unwrap()
    }
}

pub(crate) fn av_strerror(err: i32) -> String {
    let mut buf = [0u8; 1024];
    unsafe {
        ffi::av_strerror(err, buf.as_mut_ptr() as *mut _, buf.len());
    }
    String::from_utf8_lossy(&buf).to_string()
}