feat(gst): enhance GStreamer integration with new modules and improved API
This commit introduces significant enhancements to the GStreamer integration by: - Adding new modules for bins, caps, elements, pads, and plugins - Implementing a more ergonomic API with helper methods like play(), pause(), ready() - Adding support for various GStreamer plugins including app, autodetect, playback, and videoconvertscale - Improving error handling with better context attachment - Updating dependencies to latest versions including gstreamer-video 0.24.4 - Refactoring existing code to use modern Rust patterns and features
This commit is contained in:
125
gst/src/plugins/playback/playbin3.rs
Normal file
125
gst/src/plugins/playback/playbin3.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use crate::*;
|
||||
pub struct Playbin3 {
|
||||
inner: gstreamer::Element,
|
||||
}
|
||||
|
||||
impl Drop for Playbin3 {
|
||||
fn drop(&mut self) {
|
||||
let _ = self
|
||||
.inner
|
||||
.set_state(gstreamer::State::Null)
|
||||
.inspect_err(|e| {
|
||||
tracing::error!("Failed to set playbin3 to Null state on drop: {:?}", e)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Playbin3 {
|
||||
pub fn new(name: impl AsRef<str>) -> Result<Self> {
|
||||
use gstreamer::prelude::*;
|
||||
gstreamer::ElementFactory::make("playbin3")
|
||||
.name(name.as_ref())
|
||||
.build()
|
||||
.map(|element| Playbin3 { inner: element })
|
||||
.change_context(Error)
|
||||
}
|
||||
|
||||
pub fn with_uri(self, uri: impl AsRef<str>) -> Self {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner.set_property("uri", uri.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_video_sink(self, video_sink: &impl IsElement) -> Self {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner
|
||||
.set_property("video-sink", &video_sink.as_element().inner);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_text_sink(self, text_sink: &impl IsElement) -> Self {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner
|
||||
.set_property("text-sink", &text_sink.as_element().inner);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_audio_sink(self, audio_sink: &impl IsElement) -> Self {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner
|
||||
.set_property("audio-sink", &audio_sink.as_element().inner);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_volume(&self, volume: f64) {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner.set_property("volume", volume.clamp(1.0, 100.0))
|
||||
}
|
||||
|
||||
pub fn get_volume(&self) -> f64 {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner.property::<f64>("volume")
|
||||
}
|
||||
|
||||
pub fn play(&self) -> Result<()> {
|
||||
use gstreamer::prelude::*;
|
||||
self.inner
|
||||
.set_state(gstreamer::State::Playing)
|
||||
.change_context(Error)
|
||||
.attach("Failed to set playbin3 to Playing state")?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn bus(&self) -> Result<Bus> {
|
||||
let bus = self
|
||||
.inner
|
||||
.bus()
|
||||
.ok_or(Error)
|
||||
.attach("Failed to get bus from playbin3")?;
|
||||
Ok(Bus { bus })
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_playbin3() {
|
||||
use gstreamer::prelude::*;
|
||||
use tracing_subscriber::prelude::*;
|
||||
tracing_subscriber::registry()
|
||||
.with(
|
||||
tracing_subscriber::fmt::layer()
|
||||
.with_thread_ids(true)
|
||||
.with_file(true),
|
||||
)
|
||||
.init();
|
||||
tracing::info!("Linking videoconvert to appsink");
|
||||
gstreamer::init().unwrap();
|
||||
let playbin3 = Playbin3::new("test_playbin3").unwrap().with_uri("https://jellyfin.tsuba.darksailor.dev/Items/6010382cf25273e624d305907010d773/Download?api_key=036c140222464878862231ef66a2bc9c");
|
||||
// let mut video_sink = Bin::new("wgpu_video_sink");
|
||||
//
|
||||
// let video_convert = plugins::videoconvertscale::VideoConvert::new("wgpu_video_convert")
|
||||
// .expect("Create videoconvert");
|
||||
// let appsink = AppSink::new("test_appsink").expect("Create appsink");
|
||||
let appsink = plugins::autodetect::AutoVideoSink::new("test_autodetect_video_sink")
|
||||
.expect("Create autodetect video sink");
|
||||
// video_convert
|
||||
// .link(&appsink)
|
||||
// .expect("Link videoconvert to appsink");
|
||||
//
|
||||
// let sink_pad = video_convert.sink_pad();
|
||||
// let sink_pad = Pad::ghost(&sink_pad).expect("Create ghost pad from videoconvert src");
|
||||
// video_sink
|
||||
// .add(appsink)
|
||||
// .expect("Add appsink to video sink")
|
||||
// .add(video_convert)
|
||||
// .expect("Add videoconvert to video sink")
|
||||
// .add_pad(&sink_pad)
|
||||
// .expect("Add ghost pad to video sink");
|
||||
// sink_pad.activate(true).expect("Activate ghost pad");
|
||||
|
||||
let playbin3 = playbin3.with_video_sink(&appsink);
|
||||
playbin3.play().unwrap();
|
||||
let bus = playbin3.bus().unwrap();
|
||||
for msg in bus.iter_timed(None) {
|
||||
tracing::info!("{:#?}", &msg.view());
|
||||
}
|
||||
// std::thread::sleep(std::time::Duration::from_secs(5));
|
||||
}
|
||||
Reference in New Issue
Block a user