use g2g_core::{
AsyncElement, Caps, Dim, G2gError, OutputSink, PipelinePacket, PropValue, PushOutcome, Rate,
RawVideoFormat,
};
#[cfg(not(feature = "python"))]
use g2g_core::ConfigureOutcome;
use g2g_python::PyTransform;
fn rgba(w: u32, h: u32, fps: u32) -> Caps {
Caps::RawVideo {
format: RawVideoFormat::Rgba8,
width: Dim::Fixed(w),
height: Dim::Fixed(h),
framerate: Rate::Fixed(fps),
interlace: g2g_core::Interlace::Any,
}
}
#[derive(Default)]
struct CollectSink {
packets: Vec<PipelinePacket>,
}
impl OutputSink for CollectSink {
fn poll_push(
&mut self,
_cx: &mut core::task::Context<'_>,
packet_slot: &mut Option<PipelinePacket>,
) -> core::task::Poll<Result<PushOutcome, G2gError>> {
let packet = packet_slot.take().expect("poll_push without a packet");
self.packets.push(packet);
core::task::Poll::Ready(Ok(PushOutcome::Accepted))
}
}
#[test]
fn negotiates_concrete_geometry_against_any_accept() {
let el = PyTransform::new("action", "ActionTransform");
let upstream = rgba(640, 480, 30);
assert_eq!(el.intercept_caps(&upstream).unwrap(), upstream);
}
#[test]
fn rejects_a_format_outside_the_accepted_set() {
let el = PyTransform::new("action", "ActionTransform");
let nv12 = Caps::RawVideo {
format: RawVideoFormat::Nv12,
width: Dim::Fixed(640),
height: Dim::Fixed(480),
framerate: Rate::Fixed(30),
interlace: g2g_core::Interlace::Any,
};
assert!(el.intercept_caps(&nv12).is_err());
}
#[test]
fn with_accept_hosts_a_different_format() {
let nv12 = Caps::RawVideo {
format: RawVideoFormat::Nv12,
width: Dim::Any,
height: Dim::Any,
framerate: Rate::Any,
interlace: g2g_core::Interlace::Any,
};
let el = PyTransform::new("action", "ActionTransform").with_accept(nv12);
let upstream = Caps::RawVideo {
format: RawVideoFormat::Nv12,
width: Dim::Fixed(1280),
height: Dim::Fixed(720),
framerate: Rate::Fixed(25),
interlace: g2g_core::Interlace::Any,
};
assert_eq!(el.intercept_caps(&upstream).unwrap(), upstream);
}
#[cfg(not(feature = "python"))]
#[test]
fn configure_accepts_fixed_caps() {
let mut el = PyTransform::new("action", "ActionTransform");
let outcome = el.configure_pipeline(&rgba(320, 240, 15)).unwrap();
assert!(matches!(outcome, ConfigureOutcome::Accepted));
}
#[test]
fn properties_round_trip() {
let mut el = PyTransform::new("action", "ActionTransform").with_draw_label(true);
assert_eq!(el.get_property("draw-label"), Some(PropValue::Bool(true)));
assert_eq!(
el.get_property("module"),
Some(PropValue::Str("action".into()))
);
el.set_property("class", PropValue::Str("OtherTransform".into()))
.unwrap();
assert_eq!(
el.get_property("class"),
Some(PropValue::Str("OtherTransform".into()))
);
el.set_property("nope", PropValue::Bool(true)).unwrap();
assert_eq!(el.get_property("nope"), Some(PropValue::Bool(true)));
}
#[test]
fn process_before_configure_is_rejected() {
let mut el = PyTransform::new("action", "ActionTransform");
let mut sink = CollectSink::default();
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
let res = rt.block_on(el.process(PipelinePacket::Eos, &mut sink));
assert_eq!(res, Err(G2gError::NotConfigured));
}
#[cfg(not(feature = "python"))]
#[test]
fn eos_after_configure_drains_to_nothing() {
let mut el = PyTransform::new("action", "ActionTransform");
el.configure_pipeline(&rgba(320, 240, 15)).unwrap();
let mut sink = CollectSink::default();
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
rt.block_on(el.process(PipelinePacket::Eos, &mut sink))
.unwrap();
assert!(sink.packets.is_empty());
}