use crate::elements_builder::H264EncBuilder;
use anyhow::Result;
use gst::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NvPreset {
Default,
Hp,
Hq,
LowLatency,
LowLatencyHq,
LowLatencyHp,
Lossless,
LosslessHp,
}
impl NvPreset {
pub fn as_str(&self) -> &'static str {
match self {
NvPreset::Default => "default",
NvPreset::Hp => "hp",
NvPreset::Hq => "hq",
NvPreset::LowLatency => "low-latency",
NvPreset::LowLatencyHq => "low-latency-hq",
NvPreset::LowLatencyHp => "low-latency-hp",
NvPreset::Lossless => "lossless",
NvPreset::LosslessHp => "lossless-hp",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NvRateControl {
Cqp,
Vbr,
Cbr,
CbrLdHq,
CbrHq,
VbrHq,
}
impl NvRateControl {
pub fn as_str(&self) -> &'static str {
match self {
NvRateControl::Cqp => "cqp",
NvRateControl::Vbr => "vbr",
NvRateControl::Cbr => "cbr",
NvRateControl::CbrLdHq => "cbr-ld-hq",
NvRateControl::CbrHq => "cbr-hq",
NvRateControl::VbrHq => "vbr-hq",
}
}
}
#[derive(Debug, Clone)]
pub struct Xh264EncBuilder {
element: gst::Element,
}
impl Xh264EncBuilder {
pub fn new() -> Self {
let element = gst::ElementFactory::make_with_name("x264enc", Some("video_encoder")).unwrap();
element.set_property_from_str("speed-preset", "superfast"); element.set_property_from_str("tune", "zerolatency"); element.set_property("threads", 16u32); element.set_property("key-int-max", 30u32);
Self { element }
}
pub fn default() -> Self {
let mut builder = Self::new();
builder
}
pub fn with_zero_latency(mut self, zero_latency: bool) -> Self {
self.element.set_property("zerolatency", zero_latency);
self
}
}
impl H264EncBuilder for Xh264EncBuilder {
const VALID_PROFILES: &'static [&'static str] = &[];
fn with_bitrate(&mut self, bitrate: u32) -> &mut Self {
let capped_bitrate = if bitrate > 2_048_000 {
2_048_000
} else {
bitrate
};
let final_bitrate = if capped_bitrate > 1_000_000 {
capped_bitrate / 1_000
} else {
capped_bitrate
};
self.element.set_property("bitrate", final_bitrate);
self
}
fn with_bframes(&mut self, bframes: u32) -> &mut Self {
let bframes = if bframes > 4 { 4 } else { bframes };
self.element.set_property("bframes", bframes);
self
}
fn with_gop_size(&mut self, size: i32) -> &mut Self {
let gop_size = if size < -1 {
-1
} else if size > 2_147_483_647 {
2_147_483_647
} else {
size
};
self.element.set_property("gop-size", gop_size);
self
}
fn with_rate_control_mode(&mut self, rate_control: &str) -> &mut Self {
self.element.set_property_from_str("rc-mode", rate_control);
self
}
fn with_preset(&mut self, preset: &str) -> &mut Self {
self.element.set_property_from_str("preset", preset);
self
}
fn with_profile(&mut self, profile: &str) -> Result<&mut Self> {
todo!()
}
fn build(&self) -> Result<gst::Element> {
Ok(self.element.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use gst::glib::Value;
use gst::init;
#[test]
fn test_default_encoder_builder() {
init().unwrap();
let builder = Xh264EncBuilder::default();
assert_default_encoder_properties(&builder);
}
#[test]
fn test_encoder_builder_with_bitrate() {
init().unwrap();
let mut builder = Xh264EncBuilder::default();
builder.with_bitrate(1_000_000);
assert_eq!(builder.element.property::<u32>("bitrate"), 1_000_000);
}
#[test]
fn test_encoder_builder_with_gop_size() {
init().unwrap();
let mut builder = Xh264EncBuilder::default();
builder.with_gop_size(30);
assert_eq!(builder.element.property::<i32>("gop-size"), 30);
}
#[test]
fn test_encoder_builder_with_preset() {
init().unwrap();
let mut builder = Xh264EncBuilder::default();
builder.with_preset(crate::elements_builder::nvh264enc::NvPreset::Default.as_str());
assert_preset_property(&builder, "default");
}
#[test]
fn test_encoder_builder_with_rate_control() {
init().unwrap();
let mut builder = Xh264EncBuilder::default();
builder.with_rate_control_mode(crate::elements_builder::nvh264enc::NvRateControl::Cbr.as_str());
assert_rate_control_property(&builder, "cbr");
}
#[test]
fn test_encoder_builder_build() {
init().unwrap();
let result = Xh264EncBuilder::default().build();
assert!(result.is_ok());
}
fn assert_default_encoder_properties(builder: &Xh264EncBuilder) {
assert_eq!(builder.element.property::<u32>("bitrate"), 1000);
assert_eq!(builder.element.property::<i32>("gop-size"), 75);
assert_preset_property(builder, "hp");
assert_rate_control_property(builder, "cbr");
}
fn assert_preset_property(builder: &Xh264EncBuilder, expected: &str) {
assert_eq!(
builder
.element
.property::<Value>("preset")
.serialize()
.unwrap(),
expected
);
}
fn assert_rate_control_property(builder: &Xh264EncBuilder, expected: &str) {
assert_eq!(
builder
.element
.property::<Value>("rc-mode")
.serialize()
.unwrap(),
expected
);
}
}