gst-flexhlssink-rs/tests/flexhlssink.rs
2021-05-17 21:35:11 +02:00

214 lines
6.9 KiB
Rust

use gio::prelude::*;
use glib::prelude::*;
use gst::gst_info;
use gst::prelude::*;
use gst_base::prelude::*;
use once_cell::sync::Lazy;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"flexhlssink-test",
gst::DebugColorFlags::empty(),
Some("Flex HLS sink test"),
)
});
fn init() {
use std::sync::Once;
static INIT: Once = Once::new();
INIT.call_once(|| {
gst::init().unwrap();
flexhlssink::plugin_register_static().expect("flexhlssink test");
});
}
#[test]
fn test_events() {
init();
let mut h = gst_check::Harness::new_parse(
"videotestsrc is-live=true ! x264enc ! h264parse ! flexhlssink",
);
let flexhlssink = h.find_element("flexhlssink").unwrap();
let fragment_location = "test.ts".to_string();
let fragment_stream = flexhlssink
.emit_by_name("get-fragment-stream", &[&fragment_location])
.expect("successful result")
.expect("return some value")
.get::<gio::OutputStream>()
.expect("it's a gio::OutputStream value");
// write something, just to make sure it is valid!
fragment_stream
.write("TEST".as_bytes(), gio::NONE_CANCELLABLE)
.unwrap();
assert!(flexhlssink
.emit_by_name("delete-fragment", &[&fragment_location])
.expect("successful result")
.is_none());
}
#[test]
fn test_basic_element_with_video_content() {
init();
const BUFFER_NB: i32 = 600;
let pipeline = gst::Pipeline::new(Some("video_pipeline"));
let video_src = gst::ElementFactory::make("videotestsrc", Some("test_videotestsrc")).unwrap();
video_src.set_property("is-live", &true).unwrap();
let x264enc = gst::ElementFactory::make("x264enc", Some("test_x264enc")).unwrap();
let h264parse = gst::ElementFactory::make("h264parse", Some("test_h264parse")).unwrap();
let tee = gst::ElementFactory::make("tee", Some("test_tee")).unwrap();
let hls_queue = gst::ElementFactory::make("queue", Some("test_hls_queue")).unwrap();
let flexhlssink = gst::ElementFactory::make("flexhlssink", Some("test_flexhlssink")).unwrap();
flexhlssink.set_property("target-duration", &6u32).unwrap();
let app_queue = gst::ElementFactory::make("queue", Some("test_app_queue")).unwrap();
let app_sink = gst::ElementFactory::make("appsink", Some("test_sink")).unwrap();
app_sink.set_property("sync", &false).unwrap();
app_sink.set_property("async", &false).unwrap();
pipeline
.add_many(&[
&video_src,
&x264enc,
&h264parse,
&tee,
&app_queue,
&app_sink,
&hls_queue,
&flexhlssink,
])
.unwrap();
gst::Element::link_many(&[&video_src, &x264enc, &h264parse, &tee]).unwrap();
gst::Element::link_many(&[&app_queue, &app_sink]).unwrap();
gst::Element::link_many(&[&hls_queue, &flexhlssink]).unwrap();
// Link the appsink
let tee_app_pad = tee.request_pad_simple("src_%u").unwrap();
let app_queue_pad = app_queue.static_pad("sink").unwrap();
tee_app_pad.link(&app_queue_pad).unwrap();
// Link the flexhlssink branch
let tee_hls_pad = tee.request_pad_simple("src_%u").unwrap();
let hls_queue_pad = hls_queue.static_pad("sink").unwrap();
tee_hls_pad.link(&hls_queue_pad).unwrap();
let appsink = app_sink.dynamic_cast::<gst_app::AppSink>().unwrap();
appsink.set_emit_signals(true);
let (sender, receiver) = mpsc::channel();
appsink.connect_new_sample(move |appsink| {
let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
let buffer = sample.buffer().ok_or(gst::FlowError::Error)?;
//gst_info!(CAT, "TEST sample buffer[{}]", buffer.size());
sender.send(()).unwrap();
Ok(gst::FlowSuccess::Ok)
});
pipeline.set_state(gst::State::Playing).unwrap();
gst_info!(
CAT,
"flexhlssink_video_pipeline: waiting for {} buffers",
BUFFER_NB
);
for _idx in 0..BUFFER_NB {
receiver.recv().unwrap();
//gst_info!(CAT, "flexhlssink_video_pipeline: received buffer #{}", idx);
}
pipeline.set_state(gst::State::Null).unwrap();
}
#[test]
fn test_basic_element_properties() {
init();
const BUFFER_NB: i32 = 200;
let pipeline = gst::Pipeline::new(Some("audio_pipeline"));
let audio_src = gst::ElementFactory::make("audiotestsrc", Some("audiotestsrc")).unwrap();
audio_src.set_property("is-live", &true).unwrap();
audio_src.set_property("num-buffers", &BUFFER_NB).unwrap();
let tee = gst::ElementFactory::make("tee", Some("tee")).unwrap();
let hls_queue = gst::ElementFactory::make("queue", Some("hls_queue")).unwrap();
let hls_avenc_aac = gst::ElementFactory::make("avenc_aac", Some("hls_avenc_aac")).unwrap();
let flexhlssink = gst::ElementFactory::make("flexhlssink", Some("flexhlssink")).unwrap();
flexhlssink.set_property("target-duration", &6u32).unwrap();
let app_queue = gst::ElementFactory::make("queue", Some("app_queue")).unwrap();
let app_sink = gst::ElementFactory::make("appsink", Some("appsink")).unwrap();
app_sink.set_property("sync", &false).unwrap();
app_sink.set_property("async", &false).unwrap();
app_sink.set_property("emit-signals", &true).unwrap();
pipeline
.add_many(&[
&audio_src,
&tee,
&app_queue,
&app_sink,
&hls_queue,
&hls_avenc_aac,
&flexhlssink,
])
.unwrap();
gst::Element::link_many(&[&audio_src, &tee]).unwrap();
gst::Element::link_many(&[&app_queue, &app_sink]).unwrap();
gst::Element::link_many(&[&hls_queue, &hls_avenc_aac, &flexhlssink]).unwrap();
// Link the appsink
let tee_app_pad = tee.request_pad_simple("src_%u").unwrap();
let app_queue_pad = app_queue.static_pad("sink").unwrap();
tee_app_pad.link(&app_queue_pad).unwrap();
// Link the flexhlssink branch
let tee_hls_pad = tee.request_pad_simple("src_%u").unwrap();
let hls_queue_pad = hls_queue.static_pad("sink").unwrap();
tee_hls_pad.link(&hls_queue_pad).unwrap();
let appsink = app_sink.dynamic_cast::<gst_app::AppSink>().unwrap();
let (sender, receiver) = mpsc::channel();
appsink.connect_new_sample(move |appsink| {
let _sample = appsink
.emit_by_name("pull-sample", &[])
.unwrap()
.unwrap()
.get::<gst::Sample>()
.unwrap();
sender.send(()).unwrap();
Ok(gst::FlowSuccess::Ok)
});
pipeline.set_state(gst::State::Playing).unwrap();
gst_info!(CAT, "audio_pipeline: waiting for {} buffers", BUFFER_NB);
for idx in 0..BUFFER_NB {
receiver.recv().unwrap();
gst_info!(CAT, "audio_pipeline: received buffer #{}", idx);
}
pipeline.set_state(gst::State::Null).unwrap();
}