Skip to main content

ff_encode/video/codec_options/
prores.rs

1//! Apple ProRes per-codec encoding options.
2
3/// Apple ProRes encoding profile.
4///
5/// Controls quality and chroma sampling. 422 profiles use `yuv422p10le`;
6/// 4444 profiles use `yuva444p10le`.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum ProResProfile {
9    /// 422 Proxy — lowest data rate, offline editing.
10    Proxy,
11    /// 422 LT — lightweight, good for editing proxies.
12    Lt,
13    /// 422 Standard — production quality (default).
14    #[default]
15    Standard,
16    /// 422 HQ — high quality, recommended for mastering.
17    Hq,
18    /// 4444 — full chroma, supports alpha channel.
19    P4444,
20    /// 4444 XQ — maximum quality 4444 variant.
21    P4444Xq,
22}
23
24impl ProResProfile {
25    /// Returns the integer profile ID passed to `prores_ks` via `av_opt_set`.
26    pub(in crate::video) fn profile_id(self) -> u8 {
27        match self {
28            Self::Proxy => 0,
29            Self::Lt => 1,
30            Self::Standard => 2,
31            Self::Hq => 3,
32            Self::P4444 => 4,
33            Self::P4444Xq => 5,
34        }
35    }
36
37    /// Returns `true` for 4444 profiles that require `yuva444p10le` pixel format.
38    pub(in crate::video) fn is_4444(self) -> bool {
39        matches!(self, Self::P4444 | Self::P4444Xq)
40    }
41}
42
43/// Apple ProRes per-codec options.
44///
45/// Requires an FFmpeg build with `prores_ks` encoder support. Output should
46/// use a `.mov` container.
47#[derive(Debug, Clone)]
48pub struct ProResOptions {
49    /// ProRes encoding profile controlling quality and chroma sampling.
50    pub profile: ProResProfile,
51    /// Optional 4-byte FourCC vendor tag embedded in the stream.
52    ///
53    /// Set to `Some([b'a', b'p', b'p', b'l'])` to mimic Apple encoders.
54    /// `None` leaves the encoder default.
55    pub vendor: Option<[u8; 4]>,
56}
57
58impl Default for ProResOptions {
59    fn default() -> Self {
60        Self {
61            profile: ProResProfile::Standard,
62            vendor: None,
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn prores_options_default_should_have_standard_profile() {
73        let opts = ProResOptions::default();
74        assert_eq!(opts.profile, ProResProfile::Standard);
75        assert!(opts.vendor.is_none());
76    }
77
78    #[test]
79    fn prores_profile_ids_should_match_spec() {
80        assert_eq!(ProResProfile::Proxy.profile_id(), 0);
81        assert_eq!(ProResProfile::Lt.profile_id(), 1);
82        assert_eq!(ProResProfile::Standard.profile_id(), 2);
83        assert_eq!(ProResProfile::Hq.profile_id(), 3);
84        assert_eq!(ProResProfile::P4444.profile_id(), 4);
85        assert_eq!(ProResProfile::P4444Xq.profile_id(), 5);
86    }
87
88    #[test]
89    fn prores_profile_is_4444_should_return_true_for_4444_variants() {
90        assert!(!ProResProfile::Proxy.is_4444());
91        assert!(!ProResProfile::Lt.is_4444());
92        assert!(!ProResProfile::Standard.is_4444());
93        assert!(!ProResProfile::Hq.is_4444());
94        assert!(ProResProfile::P4444.is_4444());
95        assert!(ProResProfile::P4444Xq.is_4444());
96    }
97}