mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-09-26 14:00:14 +00:00
Compare commits
52 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ef77a5ae92 | ||
|
079095b55c | ||
|
2599acc681 | ||
|
671605d8ac | ||
|
01da01c9e6 | ||
|
4e30798ac7 | ||
|
ed80467ff6 | ||
|
19295f75b5 | ||
|
e02ec7a8c9 | ||
|
21ffeb5e82 | ||
|
aa86c804bd | ||
|
38071f1897 | ||
|
d429fad50d | ||
|
67e6afc628 | ||
|
0e69898faf | ||
|
45b7676d02 | ||
|
315a59e47d | ||
|
3b56f470e5 | ||
|
0d34e70e3e | ||
|
7a05ff52af | ||
|
66338881e8 | ||
|
5beb871419 | ||
|
462f4ac3b8 | ||
|
a61c50c21a | ||
|
e6d3ac4e4b | ||
|
89b9dc80dc | ||
|
9b593f626b | ||
|
605d4fbf24 | ||
|
7fa810873f | ||
|
0ffd86c37e | ||
|
ea38e022be | ||
|
23fdd2c5ad | ||
|
3ae8b48400 | ||
|
188ef1e242 | ||
|
a47a6ea76c | ||
|
e5397f5a33 | ||
|
41663f15ef | ||
|
8a9be64c3f | ||
|
3a8ae5ddd4 | ||
|
fc1e909925 | ||
|
5577e8a457 | ||
|
456ad9fb4a | ||
|
b127f93cb9 | ||
|
db1c341cdf | ||
|
c29a7638d3 | ||
|
7f07bac0c7 | ||
|
3425bcfe9d | ||
|
28cc573875 | ||
|
fedf4b664a | ||
|
d2e508eca1 | ||
|
d62d788630 | ||
|
6fd13cc807 |
120 changed files with 7440 additions and 645 deletions
|
@ -137,12 +137,12 @@ clippy:
|
|||
FEATURES=v1_16
|
||||
fi
|
||||
|
||||
cargo clippy --color=always --manifest-path $crate/Cargo.toml --features=$FEATURES -- -A clippy::redundant_pattern_matching -A clippy::single_match -A clippy::cast_lossless
|
||||
cargo clippy --color=always --manifest-path $crate/Cargo.toml --features=$FEATURES --all-targets -- -A clippy::redundant_pattern_matching -A clippy::single_match -A clippy::cast_lossless -A clippy::missing_safety_doc
|
||||
done
|
||||
# And also run over all the examples/tutorials
|
||||
- |
|
||||
cargo clippy --color=always --manifest-path examples/Cargo.toml --bins --examples --all-features -- -A clippy::redundant_pattern_matching -A clippy::single_match -A clippy::cast_lossless
|
||||
cargo clippy --color=always --manifest-path tutorials/Cargo.toml --bins --examples --all-features -- -A clippy::redundant_pattern_matching -A clippy::single_match -A clippy::cast_lossless
|
||||
cargo clippy --color=always --manifest-path examples/Cargo.toml --all-targets --all-features -- -A clippy::redundant_pattern_matching -A clippy::single_match -A clippy::cast_lossless -A clippy::missing_safety_doc
|
||||
cargo clippy --color=always --manifest-path tutorials/Cargo.toml --all-targets --all-features -- -A clippy::redundant_pattern_matching -A clippy::single_match -A clippy::cast_lossless -A clippy::missing_safety_doc
|
||||
|
||||
audit:
|
||||
extends: '.tarball_setup'
|
||||
|
|
|
@ -144,6 +144,12 @@ status = "generate"
|
|||
# bool does not signal error
|
||||
ignore = true
|
||||
|
||||
[[object.function]]
|
||||
pattern = "get_.*"
|
||||
[[object.function.parameter]]
|
||||
name = "align"
|
||||
const = true
|
||||
|
||||
[[object]]
|
||||
name = "GstAudio.AudioDecoder"
|
||||
status = "generate"
|
||||
|
|
|
@ -96,6 +96,11 @@ name = "GstRtspServer.RTSPToken"
|
|||
status = "manual"
|
||||
ref_mode = "ref"
|
||||
|
||||
[[object]]
|
||||
name = "GstRtspServer.RTSPThread"
|
||||
status = "manual"
|
||||
ref_mode = "ref"
|
||||
|
||||
[[object]]
|
||||
name = "Gst.ClockTime"
|
||||
status = "manual"
|
||||
|
@ -246,11 +251,20 @@ status = "generate"
|
|||
[object.function.return]
|
||||
bool_return_is_error = "Failed to unprepare media"
|
||||
|
||||
[[object.function]]
|
||||
name = "prepare"
|
||||
[object.function.return]
|
||||
bool_return_is_error = "Failed to prepare media"
|
||||
|
||||
[[object.function]]
|
||||
name = "unsuspend"
|
||||
[object.function.return]
|
||||
bool_return_is_error = "Failed to unsuspend media"
|
||||
|
||||
[[object.function]]
|
||||
name = "take_pipeline"
|
||||
ignore = true
|
||||
|
||||
[[object]]
|
||||
name = "GstRtspServer.RTSPMediaFactory"
|
||||
status = "generate"
|
||||
|
|
|
@ -40,6 +40,13 @@ generate = [
|
|||
"GstVideo.VideoBufferPool",
|
||||
"GstVideo.VideoPackFlags",
|
||||
"GstVideo.VideoBufferFlags",
|
||||
"GstVideo.VideoAlphaMode",
|
||||
"GstVideo.VideoChromaMode",
|
||||
"GstVideo.VideoMatrixMode",
|
||||
"GstVideo.VideoGammaMode",
|
||||
"GstVideo.VideoPrimariesMode",
|
||||
"GstVideo.VideoResamplerMethod",
|
||||
"GstVideo.VideoDitherMethod",
|
||||
]
|
||||
|
||||
manual = [
|
||||
|
|
|
@ -5,29 +5,30 @@ license = "MIT"
|
|||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
|
||||
[dependencies]
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-gl = { path = "../gstreamer-gl", optional = true }
|
||||
gstreamer-app = { path = "../gstreamer-app" }
|
||||
gstreamer-audio = { path = "../gstreamer-audio" }
|
||||
gstreamer-base = { path = "../gstreamer-base" }
|
||||
gstreamer-video = { path = "../gstreamer-video" }
|
||||
gstreamer-pbutils = { path = "../gstreamer-pbutils" }
|
||||
gstreamer-player = { path = "../gstreamer-player", optional = true }
|
||||
gstreamer-editing-services = { path = "../gstreamer-editing-services", optional = true }
|
||||
gstreamer-rtsp = { path = "../gstreamer-rtsp", optional = true }
|
||||
gstreamer-rtsp-server = { path = "../gstreamer-rtsp-server", optional = true }
|
||||
gstreamer-rtsp-server-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"], optional = true }
|
||||
gtk = { git = "https://github.com/gtk-rs/gtk", optional = true }
|
||||
gdk = { git = "https://github.com/gtk-rs/gdk", optional = true }
|
||||
gio = { git = "https://github.com/gtk-rs/gio", optional = true }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-gl = { version = "0.15", path = "../gstreamer-gl", optional = true }
|
||||
gstreamer-app = { version = "0.15", path = "../gstreamer-app" }
|
||||
gstreamer-audio = { version = "0.15", path = "../gstreamer-audio" }
|
||||
gstreamer-base = { version = "0.15", path = "../gstreamer-base" }
|
||||
gstreamer-video = { version = "0.15", path = "../gstreamer-video" }
|
||||
gstreamer-pbutils = { version = "0.15", path = "../gstreamer-pbutils" }
|
||||
gstreamer-player = { version = "0.15", path = "../gstreamer-player", optional = true }
|
||||
gstreamer-editing-services = { version = "0.15", path = "../gstreamer-editing-services", optional = true }
|
||||
gstreamer-sdp = { version = "0.15", path = "../gstreamer-sdp", optional = true }
|
||||
gstreamer-rtsp = { version = "0.15", path = "../gstreamer-rtsp", optional = true }
|
||||
gstreamer-rtsp-server = { version = "0.15", path = "../gstreamer-rtsp-server", optional = true }
|
||||
gstreamer-rtsp-server-sys = { version = "0.8", features = ["v1_8"], optional = true }
|
||||
gtk = { version = "0.8", optional = true }
|
||||
gdk = { version = "0.12", optional = true }
|
||||
gio = { version = "0.8", optional = true }
|
||||
futures = "0.3"
|
||||
byte-slice-cast = "0.3"
|
||||
failure = "0.1"
|
||||
failure_derive = "0.1"
|
||||
cairo-rs = { git = "https://github.com/gtk-rs/cairo", features=["use_glib"], optional = true }
|
||||
pango = { git = "https://github.com/gtk-rs/pango", optional = true }
|
||||
pangocairo = { git = "https://github.com/gtk-rs/pangocairo", optional = true }
|
||||
cairo-rs = { version = "0.8", features=["use_glib"], optional = true }
|
||||
pango = { version = "0.8", optional = true }
|
||||
pangocairo = { version = "0.9", optional = true }
|
||||
glutin = { version = "0.21", optional = true }
|
||||
winit = { version = "0.19", optional = true }
|
||||
lazy_static = "1.0"
|
||||
|
@ -43,7 +44,7 @@ gtksink = ["gtk", "gio"]
|
|||
gtkvideooverlay = ["gtk", "gdk", "gio"]
|
||||
gtkvideooverlay-x11 = ["gtkvideooverlay"]
|
||||
gtkvideooverlay-quartz = ["gtkvideooverlay"]
|
||||
gst-rtsp-server = ["gstreamer-rtsp-server"]
|
||||
gst-rtsp-server = ["gstreamer-rtsp-server", "gstreamer-rtsp", "gstreamer-sdp"]
|
||||
gst-rtsp-server-record = ["gstreamer-rtsp-server-sys", "gstreamer-rtsp-server", "gstreamer-rtsp", "gio"]
|
||||
v1_10 = ["gstreamer/v1_10"]
|
||||
pango-cairo = ["pango", "pangocairo", "cairo-rs"]
|
||||
|
@ -110,6 +111,10 @@ name = "rtpfecserver"
|
|||
name = "rtsp-server"
|
||||
required-features = ["gst-rtsp-server"]
|
||||
|
||||
[[bin]]
|
||||
name = "rtsp-server-subclass"
|
||||
required-features = ["gst-rtsp-server"]
|
||||
|
||||
[[bin]]
|
||||
name = "tagsetter"
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -160,7 +160,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -281,7 +281,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into()),
|
||||
|
@ -295,7 +295,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -311,7 +311,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into()),
|
||||
|
@ -325,7 +325,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -594,7 +594,7 @@ impl App {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -144,7 +144,6 @@ fn create_ui(app: >k::Application) {
|
|||
// simplifies the code within the callback. What this actually does, however, is creating
|
||||
// a memory leak.
|
||||
let video_overlay = sink
|
||||
.clone()
|
||||
.dynamic_cast::<gst_video::VideoOverlay>()
|
||||
.unwrap()
|
||||
.downgrade();
|
||||
|
|
|
@ -213,7 +213,6 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
})
|
||||
.unwrap();
|
||||
|
||||
let drawer_clone = drawer.clone();
|
||||
// Add a signal handler to the overlay's "caps-changed" signal. This could e.g.
|
||||
// be called when the sink that we render to does not support resizing the image
|
||||
// itself - but the user just changed the window-size. The element after the overlay
|
||||
|
@ -226,7 +225,6 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
let _overlay = args[0].get::<gst::Element>().unwrap().unwrap();
|
||||
let caps = args[1].get::<gst::Caps>().unwrap().unwrap();
|
||||
|
||||
let drawer = &drawer_clone;
|
||||
let mut drawer = drawer.lock().unwrap();
|
||||
drawer.info = Some(gst_video::VideoInfo::from_caps(&caps).unwrap());
|
||||
|
||||
|
@ -257,7 +255,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -275,7 +275,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -146,9 +146,8 @@ fn example_main() -> Result<(), Error> {
|
|||
let sinkpad = get_static_pad(&sink, "sink")?;
|
||||
srcpad.link(&sinkpad)?;
|
||||
|
||||
let convclone = conv.clone();
|
||||
src.connect_pad_added(move |decodebin, src_pad| {
|
||||
match connect_decodebin_pad(&src_pad, &convclone) {
|
||||
src.connect_pad_added(
|
||||
move |decodebin, src_pad| match connect_decodebin_pad(&src_pad, &conv) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
gst_element_error!(
|
||||
|
@ -158,8 +157,8 @@ fn example_main() -> Result<(), Error> {
|
|||
["{}", err]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let video_caps = gst::Caps::new_simple("video/x-raw", &[]);
|
||||
|
||||
|
@ -199,7 +198,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
481
examples/src/bin/rtsp-server-subclass.rs
Normal file
481
examples/src/bin/rtsp-server-subclass.rs
Normal file
|
@ -0,0 +1,481 @@
|
|||
// This example demonstrates how to set up a rtsp server using GStreamer
|
||||
// and extending the behaviour by subclass RTSPMediaFactory and RTSPMedia.
|
||||
// For this, the example creates a videotestsrc pipeline manually to be used
|
||||
// by the RTSP server for providing data, and adds a custom attribute to the
|
||||
// SDP provided to the client.
|
||||
//
|
||||
// It also comes with a custom RTSP server/client subclass for hooking into
|
||||
// the client machinery and printing some status.
|
||||
|
||||
extern crate gstreamer as gst;
|
||||
|
||||
extern crate gstreamer_rtsp as gst_rtsp;
|
||||
extern crate gstreamer_rtsp_server as gst_rtsp_server;
|
||||
extern crate gstreamer_sdp as gst_sdp;
|
||||
use gst_rtsp_server::prelude::*;
|
||||
|
||||
#[macro_use]
|
||||
extern crate glib;
|
||||
|
||||
extern crate failure;
|
||||
use failure::Error;
|
||||
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
|
||||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Fail)]
|
||||
#[fail(display = "Could not get mount points")]
|
||||
struct NoMountPoints;
|
||||
|
||||
#[derive(Debug, Fail)]
|
||||
#[fail(display = "Usage: {} LAUNCH_LINE", _0)]
|
||||
struct UsageError(String);
|
||||
|
||||
fn main_loop() -> Result<(), Error> {
|
||||
let main_loop = glib::MainLoop::new(None, false);
|
||||
let server = server::Server::new();
|
||||
// Much like HTTP servers, RTSP servers have multiple endpoints that
|
||||
// provide different streams. Here, we ask our server to give
|
||||
// us a reference to his list of endpoints, so we can add our
|
||||
// test endpoint, providing the pipeline from the cli.
|
||||
let mounts = server.get_mount_points().ok_or(NoMountPoints)?;
|
||||
|
||||
// Next, we create our custom factory for the endpoint we want to create.
|
||||
// The job of the factory is to create a new pipeline for each client that
|
||||
// connects, or (if configured to do so) to reuse an existing pipeline.
|
||||
let factory = media_factory::Factory::new();
|
||||
// This setting specifies whether each connecting client gets the output
|
||||
// of a new instance of the pipeline, or whether all connected clients share
|
||||
// the output of the same pipeline.
|
||||
// If you want to stream a fixed video you have stored on the server to any
|
||||
// client, you would not set this to shared here (since every client wants
|
||||
// to start at the beginning of the video). But if you want to distribute
|
||||
// a live source, you will probably want to set this to shared, to save
|
||||
// computing and memory capacity on the server.
|
||||
factory.set_shared(true);
|
||||
|
||||
// Now we add a new mount-point and tell the RTSP server to serve the content
|
||||
// provided by the factory we configured above, when a client connects to
|
||||
// this specific path.
|
||||
mounts.add_factory("/test", &factory);
|
||||
|
||||
// Attach the server to our main context.
|
||||
// A main context is the thing where other stuff is registering itself for its
|
||||
// events (e.g. sockets, GStreamer bus, ...) and the main loop is something that
|
||||
// polls the main context for its events and dispatches them to whoever is
|
||||
// interested in them. In this example, we only do have one, so we can
|
||||
// leave the context parameter empty, it will automatically select
|
||||
// the default one.
|
||||
let id = server.attach(None);
|
||||
|
||||
println!(
|
||||
"Stream ready at rtsp://127.0.0.1:{}/test",
|
||||
server.get_bound_port()
|
||||
);
|
||||
|
||||
// Start the mainloop. From this point on, the server will start to serve
|
||||
// our quality content to connecting clients.
|
||||
main_loop.run();
|
||||
|
||||
glib::source_remove(id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Our custom media factory that creates a media input manually
|
||||
mod media_factory {
|
||||
use super::*;
|
||||
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
|
||||
extern crate gstreamer_rtsp_server as gst_rtsp_server;
|
||||
use gst_rtsp_server::subclass::prelude::*;
|
||||
|
||||
// In the imp submodule we include the actual implementation
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
// This is the private data of our factory
|
||||
pub struct Factory {}
|
||||
|
||||
// This trait registers our type with the GObject object system and
|
||||
// provides the entry points for creating a new instance and setting
|
||||
// up the class data
|
||||
impl ObjectSubclass for Factory {
|
||||
const NAME: &'static str = "RsRTSPMediaFactory";
|
||||
type ParentType = gst_rtsp_server::RTSPMediaFactory;
|
||||
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
// This macro provides some boilerplate
|
||||
glib_object_subclass!();
|
||||
|
||||
// Called when a new instance is to be created. We need to return an instance
|
||||
// of our struct here.
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of glib::Object virtual methods
|
||||
impl ObjectImpl for Factory {
|
||||
// This macro provides some boilerplate.
|
||||
glib_object_impl!();
|
||||
|
||||
fn constructed(&self, obj: &glib::Object) {
|
||||
self.parent_constructed(obj);
|
||||
|
||||
let factory = obj
|
||||
.downcast_ref::<gst_rtsp_server::RTSPMediaFactory>()
|
||||
.unwrap();
|
||||
|
||||
// All media created by this factory are our custom media type. This would
|
||||
// not require a media factory subclass and can also be called on the normal
|
||||
// RTSPMediaFactory.
|
||||
factory.set_media_gtype(super::media::Media::static_type());
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of gst_rtsp_server::RTSPMediaFactory virtual methods
|
||||
impl RTSPMediaFactoryImpl for Factory {
|
||||
fn create_element(
|
||||
&self,
|
||||
_factory: &gst_rtsp_server::RTSPMediaFactory,
|
||||
_url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<gst::Element> {
|
||||
// Create a simple VP8 videotestsrc input
|
||||
let bin = gst::Bin::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None).unwrap();
|
||||
let enc = gst::ElementFactory::make("vp8enc", None).unwrap();
|
||||
|
||||
// The names of the payloaders must be payX
|
||||
let pay = gst::ElementFactory::make("rtpvp8pay", Some("pay0")).unwrap();
|
||||
|
||||
// Configure the videotestsrc live
|
||||
src.set_property("is-live", &true).unwrap();
|
||||
|
||||
// Produce encoded data as fast as possible
|
||||
enc.set_property("deadline", &1i64).unwrap();
|
||||
|
||||
bin.add_many(&[&src, &enc, &pay]).unwrap();
|
||||
gst::Element::link_many(&[&src, &enc, &pay]).unwrap();
|
||||
|
||||
Some(bin.upcast())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This here defines the public interface of our factory and implements
|
||||
// the corresponding traits so that it behaves like any other RTSPMediaFactory
|
||||
glib_wrapper! {
|
||||
pub struct Factory(
|
||||
Object<
|
||||
gst::subclass::ElementInstanceStruct<imp::Factory>,
|
||||
subclass::simple::ClassStruct<imp::Factory>,
|
||||
FactoryClass
|
||||
>
|
||||
) @extends gst_rtsp_server::RTSPMediaFactory;
|
||||
|
||||
match fn {
|
||||
get_type => || imp::Factory::get_type().to_glib(),
|
||||
}
|
||||
}
|
||||
|
||||
// Factories must be Send+Sync, and ours is
|
||||
unsafe impl Send for Factory {}
|
||||
unsafe impl Sync for Factory {}
|
||||
|
||||
impl Factory {
|
||||
// Creates a new instance of our factory
|
||||
pub fn new() -> Factory {
|
||||
glib::Object::new(Self::static_type(), &[])
|
||||
.expect("Failed to create factory")
|
||||
.downcast()
|
||||
.expect("Created factory is of wrong type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Our custom media subclass that adds a custom attribute to the SDP returned by DESCRIBE
|
||||
mod media {
|
||||
use super::*;
|
||||
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
|
||||
extern crate gstreamer_rtsp_server as gst_rtsp_server;
|
||||
use gst_rtsp_server::subclass::prelude::*;
|
||||
|
||||
// In the imp submodule we include the actual implementation
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
// This is the private data of our media
|
||||
pub struct Media {}
|
||||
|
||||
// This trait registers our type with the GObject object system and
|
||||
// provides the entry points for creating a new instance and setting
|
||||
// up the class data
|
||||
impl ObjectSubclass for Media {
|
||||
const NAME: &'static str = "RsRTSPMedia";
|
||||
type ParentType = gst_rtsp_server::RTSPMedia;
|
||||
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
// This macro provides some boilerplate
|
||||
glib_object_subclass!();
|
||||
|
||||
// Called when a new instance is to be created. We need to return an instance
|
||||
// of our struct here.
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of glib::Object virtual methods
|
||||
impl ObjectImpl for Media {
|
||||
// This macro provides some boilerplate.
|
||||
glib_object_impl!();
|
||||
}
|
||||
|
||||
// Implementation of gst_rtsp_server::RTSPMedia virtual methods
|
||||
impl RTSPMediaImpl for Media {
|
||||
fn setup_sdp(
|
||||
&self,
|
||||
media: &gst_rtsp_server::RTSPMedia,
|
||||
sdp: &mut gst_sdp::SDPMessageRef,
|
||||
info: &gst_rtsp_server::subclass::rtsp_media::SDPInfo,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.parent_setup_sdp(media, sdp, info)?;
|
||||
|
||||
sdp.add_attribute("my-custom-attribute", Some("has-a-value"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This here defines the public interface of our factory and implements
|
||||
// the corresponding traits so that it behaves like any other RTSPMedia
|
||||
glib_wrapper! {
|
||||
pub struct Media(
|
||||
Object<
|
||||
gst::subclass::ElementInstanceStruct<imp::Media>,
|
||||
subclass::simple::ClassStruct<imp::Media>,
|
||||
MediaClass
|
||||
>
|
||||
) @extends gst_rtsp_server::RTSPMedia;
|
||||
|
||||
match fn {
|
||||
get_type => || imp::Media::get_type().to_glib(),
|
||||
}
|
||||
}
|
||||
|
||||
// Medias must be Send+Sync, and ours is
|
||||
unsafe impl Send for Media {}
|
||||
unsafe impl Sync for Media {}
|
||||
}
|
||||
|
||||
// Our custom RTSP server subclass that reports when clients are connecting and uses
|
||||
// our custom RTSP client subclass for each client
|
||||
mod server {
|
||||
use super::*;
|
||||
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
|
||||
extern crate gstreamer_rtsp_server as gst_rtsp_server;
|
||||
use gst_rtsp_server::subclass::prelude::*;
|
||||
|
||||
// In the imp submodule we include the actual implementation
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
// This is the private data of our server
|
||||
pub struct Server {}
|
||||
|
||||
// This trait registers our type with the GObject object system and
|
||||
// provides the entry points for creating a new instance and setting
|
||||
// up the class data
|
||||
impl ObjectSubclass for Server {
|
||||
const NAME: &'static str = "RsRTSPServer";
|
||||
type ParentType = gst_rtsp_server::RTSPServer;
|
||||
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
// This macro provides some boilerplate
|
||||
glib_object_subclass!();
|
||||
|
||||
// Called when a new instance is to be created. We need to return an instance
|
||||
// of our struct here.
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of glib::Object virtual methods
|
||||
impl ObjectImpl for Server {
|
||||
// This macro provides some boilerplate.
|
||||
glib_object_impl!();
|
||||
}
|
||||
|
||||
// Implementation of gst_rtsp_server::RTSPServer virtual methods
|
||||
impl RTSPServerImpl for Server {
|
||||
fn create_client(
|
||||
&self,
|
||||
server: &gst_rtsp_server::RTSPServer,
|
||||
) -> Option<gst_rtsp_server::RTSPClient> {
|
||||
let client = super::client::Client::new();
|
||||
|
||||
// Duplicated from the default implementation
|
||||
client.set_session_pool(server.get_session_pool().as_ref());
|
||||
client.set_mount_points(server.get_mount_points().as_ref());
|
||||
client.set_auth(server.get_auth().as_ref());
|
||||
client.set_thread_pool(server.get_thread_pool().as_ref());
|
||||
|
||||
Some(client.upcast())
|
||||
}
|
||||
|
||||
fn client_connected(
|
||||
&self,
|
||||
server: &gst_rtsp_server::RTSPServer,
|
||||
client: &gst_rtsp_server::RTSPClient,
|
||||
) {
|
||||
self.parent_client_connected(server, client);
|
||||
println!("Client {:?} connected", client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This here defines the public interface of our factory and implements
|
||||
// the corresponding traits so that it behaves like any other RTSPServer
|
||||
glib_wrapper! {
|
||||
pub struct Server(
|
||||
Object<
|
||||
gst::subclass::ElementInstanceStruct<imp::Server>,
|
||||
subclass::simple::ClassStruct<imp::Server>,
|
||||
ServerClass
|
||||
>
|
||||
) @extends gst_rtsp_server::RTSPServer;
|
||||
|
||||
match fn {
|
||||
get_type => || imp::Server::get_type().to_glib(),
|
||||
}
|
||||
}
|
||||
|
||||
// Servers must be Send+Sync, and ours is
|
||||
unsafe impl Send for Server {}
|
||||
unsafe impl Sync for Server {}
|
||||
|
||||
impl Server {
|
||||
// Creates a new instance of our factory
|
||||
pub fn new() -> Server {
|
||||
glib::Object::new(Self::static_type(), &[])
|
||||
.expect("Failed to create server")
|
||||
.downcast()
|
||||
.expect("Created server is of wrong type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Our custom RTSP client subclass.
|
||||
mod client {
|
||||
use super::*;
|
||||
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
|
||||
extern crate gstreamer_rtsp_server as gst_rtsp_server;
|
||||
use gst_rtsp_server::subclass::prelude::*;
|
||||
|
||||
// In the imp submodule we include the actual implementation
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
// This is the private data of our server
|
||||
pub struct Client {}
|
||||
|
||||
// This trait registers our type with the GObject object system and
|
||||
// provides the entry points for creating a new instance and setting
|
||||
// up the class data
|
||||
impl ObjectSubclass for Client {
|
||||
const NAME: &'static str = "RsRTSPClient";
|
||||
type ParentType = gst_rtsp_server::RTSPClient;
|
||||
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
// This macro provides some boilerplate
|
||||
glib_object_subclass!();
|
||||
|
||||
// Called when a new instance is to be created. We need to return an instance
|
||||
// of our struct here.
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of glib::Object virtual methods
|
||||
impl ObjectImpl for Client {
|
||||
// This macro provides some boilerplate.
|
||||
glib_object_impl!();
|
||||
}
|
||||
|
||||
// Implementation of gst_rtsp_server::RTSPClient virtual methods
|
||||
impl RTSPClientImpl for Client {
|
||||
fn closed(&self, client: &gst_rtsp_server::RTSPClient) {
|
||||
self.parent_closed(client);
|
||||
println!("Client {:?} closed", client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This here defines the public interface of our factory and implements
|
||||
// the corresponding traits so that it behaves like any other RTSPClient
|
||||
glib_wrapper! {
|
||||
pub struct Client(
|
||||
Object<
|
||||
gst::subclass::ElementInstanceStruct<imp::Client>,
|
||||
subclass::simple::ClassStruct<imp::Client>,
|
||||
ClientClass
|
||||
>
|
||||
) @extends gst_rtsp_server::RTSPClient;
|
||||
|
||||
match fn {
|
||||
get_type => || imp::Client::get_type().to_glib(),
|
||||
}
|
||||
}
|
||||
|
||||
// Clients must be Send+Sync, and ours is
|
||||
unsafe impl Send for Client {}
|
||||
unsafe impl Sync for Client {}
|
||||
|
||||
impl Client {
|
||||
// Creates a new instance of our factory
|
||||
pub fn new() -> Client {
|
||||
glib::Object::new(Self::static_type(), &[])
|
||||
.expect("Failed to create client")
|
||||
.downcast()
|
||||
.expect("Created client is of wrong type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn example_main() -> Result<(), Error> {
|
||||
gst::init()?;
|
||||
main_loop()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match examples_common::run(example_main) {
|
||||
Ok(r) => r,
|
||||
Err(e) => eprintln!("Error! {}", e),
|
||||
}
|
||||
}
|
|
@ -385,7 +385,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -109,7 +109,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.unwrap_or_else(|| "None".into())
|
||||
.to_string(),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -175,7 +175,7 @@ fn example_main() -> Result<(), Error> {
|
|||
.map(|s| String::from(s.get_path_string()))
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: Some(err.get_debug().unwrap().to_string()),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-app"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer App library"
|
||||
|
@ -13,19 +13,26 @@ keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
futures-core = "0.3"
|
||||
futures-sink = "0.3"
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-app-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-base = { path = "../gstreamer-base" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-app-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-base = { version = "0.15", path = "../gstreamer-base" }
|
||||
lazy_static = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
futures-util = { version = "0.3", features = ["sink"] }
|
||||
futures-executor = "0.3"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
v1_10 = ["gstreamer/v1_10", "gstreamer-base/v1_10", "gstreamer-app-sys/v1_10"]
|
||||
|
|
|
@ -12,14 +12,32 @@ use glib::signal::SignalHandlerId;
|
|||
use glib::translate::*;
|
||||
use glib_sys::gpointer;
|
||||
use gst;
|
||||
use gst::gst_element_error;
|
||||
use gst_app_sys;
|
||||
use gst_sys;
|
||||
use std::boxed::Box as Box_;
|
||||
use std::cell::RefCell;
|
||||
use std::mem::transmute;
|
||||
use std::panic;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use AppSink;
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
use {
|
||||
futures_core::Stream,
|
||||
std::{
|
||||
pin::Pin,
|
||||
sync::{Arc, Mutex},
|
||||
task::{Context, Poll, Waker},
|
||||
},
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_ONCE_QUARK: glib::Quark =
|
||||
glib::Quark::from_string("gstreamer-rs-app-sink-callbacks");
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct AppSinkCallbacks {
|
||||
eos: Option<RefCell<Box<dyn FnMut(&AppSink) + Send + 'static>>>,
|
||||
|
@ -33,6 +51,7 @@ pub struct AppSinkCallbacks {
|
|||
Box<dyn FnMut(&AppSink) -> Result<gst::FlowSuccess, gst::FlowError> + Send + 'static>,
|
||||
>,
|
||||
>,
|
||||
panicked: AtomicBool,
|
||||
callbacks: gst_app_sys::GstAppSinkCallbacks,
|
||||
}
|
||||
|
||||
|
@ -107,6 +126,7 @@ impl AppSinkCallbacksBuilder {
|
|||
eos: self.eos,
|
||||
new_preroll: self.new_preroll,
|
||||
new_sample: self.new_sample,
|
||||
panicked: AtomicBool::new(false),
|
||||
callbacks: gst_app_sys::GstAppSinkCallbacks {
|
||||
eos: if have_eos { Some(trampoline_eos) } else { None },
|
||||
new_preroll: if have_new_preroll {
|
||||
|
@ -130,11 +150,37 @@ impl AppSinkCallbacksBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn post_panic_error_message(element: &AppSink, err: &dyn std::any::Any) {
|
||||
if let Some(cause) = err.downcast_ref::<&str>() {
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
|
||||
} else if let Some(cause) = err.downcast_ref::<String>() {
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
|
||||
} else {
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn trampoline_eos(appsink: *mut gst_app_sys::GstAppSink, callbacks: gpointer) {
|
||||
let callbacks = &*(callbacks as *const AppSinkCallbacks);
|
||||
let element: AppSink = from_glib_borrow(appsink);
|
||||
|
||||
if callbacks.panicked.load(Ordering::Relaxed) {
|
||||
let element: AppSink = from_glib_borrow(appsink);
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ref eos) = callbacks.eos {
|
||||
(&mut *eos.borrow_mut())(&from_glib_borrow(appsink))
|
||||
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
(&mut *eos.borrow_mut())(&element)
|
||||
}));
|
||||
match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
callbacks.panicked.store(true, Ordering::Relaxed);
|
||||
post_panic_error_message(&element, &err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,9 +189,27 @@ unsafe extern "C" fn trampoline_new_preroll(
|
|||
callbacks: gpointer,
|
||||
) -> gst_sys::GstFlowReturn {
|
||||
let callbacks = &*(callbacks as *const AppSinkCallbacks);
|
||||
let element: AppSink = from_glib_borrow(appsink);
|
||||
|
||||
if callbacks.panicked.load(Ordering::Relaxed) {
|
||||
let element: AppSink = from_glib_borrow(appsink);
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
return gst::FlowReturn::Error.to_glib();
|
||||
}
|
||||
|
||||
let ret = if let Some(ref new_preroll) = callbacks.new_preroll {
|
||||
(&mut *new_preroll.borrow_mut())(&from_glib_borrow(appsink)).into()
|
||||
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
(&mut *new_preroll.borrow_mut())(&element).into()
|
||||
}));
|
||||
match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
callbacks.panicked.store(true, Ordering::Relaxed);
|
||||
post_panic_error_message(&element, &err);
|
||||
|
||||
gst::FlowReturn::Error
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gst::FlowReturn::Error
|
||||
};
|
||||
|
@ -158,9 +222,27 @@ unsafe extern "C" fn trampoline_new_sample(
|
|||
callbacks: gpointer,
|
||||
) -> gst_sys::GstFlowReturn {
|
||||
let callbacks = &*(callbacks as *const AppSinkCallbacks);
|
||||
let element: AppSink = from_glib_borrow(appsink);
|
||||
|
||||
if callbacks.panicked.load(Ordering::Relaxed) {
|
||||
let element: AppSink = from_glib_borrow(appsink);
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
return gst::FlowReturn::Error.to_glib();
|
||||
}
|
||||
|
||||
let ret = if let Some(ref new_sample) = callbacks.new_sample {
|
||||
(&mut *new_sample.borrow_mut())(&from_glib_borrow(appsink)).into()
|
||||
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
(&mut *new_sample.borrow_mut())(&element).into()
|
||||
}));
|
||||
match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
callbacks.panicked.store(true, Ordering::Relaxed);
|
||||
post_panic_error_message(&element, &err);
|
||||
|
||||
gst::FlowReturn::Error
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gst::FlowReturn::Error
|
||||
};
|
||||
|
@ -175,8 +257,26 @@ unsafe extern "C" fn destroy_callbacks(ptr: gpointer) {
|
|||
impl AppSink {
|
||||
pub fn set_callbacks(&self, callbacks: AppSinkCallbacks) {
|
||||
unsafe {
|
||||
let sink = self.to_glib_none().0;
|
||||
|
||||
// This is not thread-safe before 1.16.3, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/merge_requests/570
|
||||
if gst::version() < (1, 16, 3, 0) {
|
||||
if !gobject_sys::g_object_get_qdata(sink as *mut _, SET_ONCE_QUARK.to_glib())
|
||||
.is_null()
|
||||
{
|
||||
panic!("AppSink callbacks can only be set once");
|
||||
}
|
||||
|
||||
gobject_sys::g_object_set_qdata(
|
||||
sink as *mut _,
|
||||
SET_ONCE_QUARK.to_glib(),
|
||||
1 as *mut _,
|
||||
);
|
||||
}
|
||||
|
||||
gst_app_sys::gst_app_sink_set_callbacks(
|
||||
self.to_glib_none().0,
|
||||
sink,
|
||||
mut_override(&callbacks.callbacks),
|
||||
Box::into_raw(Box::new(callbacks)) as *mut _,
|
||||
Some(destroy_callbacks),
|
||||
|
@ -217,6 +317,11 @@ impl AppSink {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
pub fn stream(&self) -> AppSinkStream {
|
||||
AppSinkStream::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn new_sample_trampoline<
|
||||
|
@ -240,3 +345,116 @@ unsafe extern "C" fn new_preroll_trampoline<
|
|||
let ret: gst::FlowReturn = f(&from_glib_borrow(this)).into();
|
||||
ret.to_glib()
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
#[derive(Debug)]
|
||||
pub struct AppSinkStream {
|
||||
app_sink: AppSink,
|
||||
waker_reference: Arc<Mutex<Option<Waker>>>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
impl AppSinkStream {
|
||||
fn new(app_sink: &AppSink) -> Self {
|
||||
skip_assert_initialized!();
|
||||
|
||||
let app_sink = app_sink.clone();
|
||||
let waker_reference = Arc::new(Mutex::new(None as Option<Waker>));
|
||||
|
||||
app_sink.set_callbacks(
|
||||
AppSinkCallbacks::new()
|
||||
.new_sample({
|
||||
let waker_reference = Arc::clone(&waker_reference);
|
||||
|
||||
move |_| {
|
||||
if let Some(waker) = waker_reference.lock().unwrap().take() {
|
||||
waker.wake();
|
||||
}
|
||||
|
||||
Ok(gst::FlowSuccess::Ok)
|
||||
}
|
||||
})
|
||||
.eos({
|
||||
let waker_reference = Arc::clone(&waker_reference);
|
||||
|
||||
move |_| {
|
||||
if let Some(waker) = waker_reference.lock().unwrap().take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
})
|
||||
.build(),
|
||||
);
|
||||
|
||||
Self {
|
||||
app_sink,
|
||||
waker_reference,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
impl Drop for AppSinkStream {
|
||||
fn drop(&mut self) {
|
||||
// This is not thread-safe before 1.16.3, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/merge_requests/570
|
||||
if gst::version() >= (1, 16, 3, 0) {
|
||||
self.app_sink.set_callbacks(AppSinkCallbacks::new().build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
impl Stream for AppSinkStream {
|
||||
type Item = gst::Sample;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
let mut waker = self.waker_reference.lock().unwrap();
|
||||
|
||||
self.app_sink
|
||||
.try_pull_sample(gst::ClockTime::from_mseconds(0))
|
||||
.map(|sample| Poll::Ready(Some(sample)))
|
||||
.unwrap_or_else(|| {
|
||||
if self.app_sink.is_eos() {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
|
||||
waker.replace(context.waker().to_owned());
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10"))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures_util::StreamExt;
|
||||
use gst::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_app_sink_stream() {
|
||||
gst::init().unwrap();
|
||||
|
||||
let videotestsrc = gst::ElementFactory::make("videotestsrc", None).unwrap();
|
||||
let appsink = gst::ElementFactory::make("appsink", None).unwrap();
|
||||
|
||||
videotestsrc.set_property("num-buffers", &5).unwrap();
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
pipeline.add(&videotestsrc).unwrap();
|
||||
pipeline.add(&appsink).unwrap();
|
||||
|
||||
videotestsrc.link(&appsink).unwrap();
|
||||
|
||||
let app_sink_stream = appsink.dynamic_cast::<AppSink>().unwrap().stream();
|
||||
let samples_future = app_sink_stream.collect::<Vec<gst::Sample>>();
|
||||
|
||||
pipeline.set_state(gst::State::Playing).unwrap();
|
||||
let samples = futures_executor::block_on(samples_future);
|
||||
pipeline.set_state(gst::State::Null).unwrap();
|
||||
|
||||
assert_eq!(samples.len(), 5);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,20 +6,34 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use futures_sink::Sink;
|
||||
use glib::translate::*;
|
||||
use glib_sys::{gboolean, gpointer};
|
||||
use gst;
|
||||
use gst::gst_element_error;
|
||||
|
||||
use gst_app_sys;
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use std::panic;
|
||||
use std::pin::Pin;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll, Waker};
|
||||
use AppSrc;
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_ONCE_QUARK: glib::Quark =
|
||||
glib::Quark::from_string("gstreamer-rs-app-src-callbacks");
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct AppSrcCallbacks {
|
||||
need_data: Option<RefCell<Box<dyn FnMut(&AppSrc, u32) + Send + 'static>>>,
|
||||
enough_data: Option<Box<dyn Fn(&AppSrc) + Send + Sync + 'static>>,
|
||||
seek_data: Option<Box<dyn Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>>,
|
||||
panicked: AtomicBool,
|
||||
callbacks: gst_app_sys::GstAppSrcCallbacks,
|
||||
}
|
||||
|
||||
|
@ -80,6 +94,7 @@ impl AppSrcCallbacksBuilder {
|
|||
need_data: self.need_data,
|
||||
enough_data: self.enough_data,
|
||||
seek_data: self.seek_data,
|
||||
panicked: AtomicBool::new(false),
|
||||
callbacks: gst_app_sys::GstAppSrcCallbacks {
|
||||
need_data: if have_need_data {
|
||||
Some(trampoline_need_data)
|
||||
|
@ -107,15 +122,41 @@ impl AppSrcCallbacksBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn post_panic_error_message(element: &AppSrc, err: &dyn std::any::Any) {
|
||||
if let Some(cause) = err.downcast_ref::<&str>() {
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
|
||||
} else if let Some(cause) = err.downcast_ref::<String>() {
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked: {}", cause]);
|
||||
} else {
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn trampoline_need_data(
|
||||
appsrc: *mut gst_app_sys::GstAppSrc,
|
||||
length: u32,
|
||||
callbacks: gpointer,
|
||||
) {
|
||||
let callbacks = &*(callbacks as *const AppSrcCallbacks);
|
||||
let element: AppSrc = from_glib_borrow(appsrc);
|
||||
|
||||
if callbacks.panicked.load(Ordering::Relaxed) {
|
||||
let element: AppSrc = from_glib_borrow(appsrc);
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ref need_data) = callbacks.need_data {
|
||||
(&mut *need_data.borrow_mut())(&from_glib_borrow(appsrc), length);
|
||||
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
(&mut *need_data.borrow_mut())(&element, length)
|
||||
}));
|
||||
match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
callbacks.panicked.store(true, Ordering::Relaxed);
|
||||
post_panic_error_message(&element, &err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,9 +165,23 @@ unsafe extern "C" fn trampoline_enough_data(
|
|||
callbacks: gpointer,
|
||||
) {
|
||||
let callbacks = &*(callbacks as *const AppSrcCallbacks);
|
||||
let element: AppSrc = from_glib_borrow(appsrc);
|
||||
|
||||
if callbacks.panicked.load(Ordering::Relaxed) {
|
||||
let element: AppSrc = from_glib_borrow(appsrc);
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ref enough_data) = callbacks.enough_data {
|
||||
(*enough_data)(&from_glib_borrow(appsrc));
|
||||
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| (*enough_data)(&element)));
|
||||
match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
callbacks.panicked.store(true, Ordering::Relaxed);
|
||||
post_panic_error_message(&element, &err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,9 +191,26 @@ unsafe extern "C" fn trampoline_seek_data(
|
|||
callbacks: gpointer,
|
||||
) -> gboolean {
|
||||
let callbacks = &*(callbacks as *const AppSrcCallbacks);
|
||||
let element: AppSrc = from_glib_borrow(appsrc);
|
||||
|
||||
if callbacks.panicked.load(Ordering::Relaxed) {
|
||||
let element: AppSrc = from_glib_borrow(appsrc);
|
||||
gst_element_error!(&element, gst::LibraryError::Failed, ["Panicked"]);
|
||||
return false.to_glib();
|
||||
}
|
||||
|
||||
let ret = if let Some(ref seek_data) = callbacks.seek_data {
|
||||
(*seek_data)(&from_glib_borrow(appsrc), offset)
|
||||
let result =
|
||||
panic::catch_unwind(panic::AssertUnwindSafe(|| (*seek_data)(&element, offset)));
|
||||
match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
callbacks.panicked.store(true, Ordering::Relaxed);
|
||||
post_panic_error_message(&element, &err);
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
@ -196,8 +268,25 @@ impl AppSrc {
|
|||
|
||||
pub fn set_callbacks(&self, callbacks: AppSrcCallbacks) {
|
||||
unsafe {
|
||||
let src = self.to_glib_none().0;
|
||||
// This is not thread-safe before 1.16.3, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/merge_requests/570
|
||||
if gst::version() < (1, 16, 3, 0) {
|
||||
if !gobject_sys::g_object_get_qdata(src as *mut _, SET_ONCE_QUARK.to_glib())
|
||||
.is_null()
|
||||
{
|
||||
panic!("AppSrc callbacks can only be set once");
|
||||
}
|
||||
|
||||
gobject_sys::g_object_set_qdata(
|
||||
src as *mut _,
|
||||
SET_ONCE_QUARK.to_glib(),
|
||||
1 as *mut _,
|
||||
);
|
||||
}
|
||||
|
||||
gst_app_sys::gst_app_src_set_callbacks(
|
||||
self.to_glib_none().0,
|
||||
src,
|
||||
mut_override(&callbacks.callbacks),
|
||||
Box::into_raw(Box::new(callbacks)) as *mut _,
|
||||
Some(destroy_callbacks),
|
||||
|
@ -227,4 +316,156 @@ impl AppSrc {
|
|||
(from_glib(min.assume_init()), from_glib(max.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sink(&self) -> AppSrcSink {
|
||||
AppSrcSink::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppSrcSink {
|
||||
app_src: AppSrc,
|
||||
waker_reference: Arc<Mutex<Option<Waker>>>,
|
||||
}
|
||||
|
||||
impl AppSrcSink {
|
||||
fn new(app_src: &AppSrc) -> Self {
|
||||
skip_assert_initialized!();
|
||||
|
||||
let app_src = app_src.clone();
|
||||
let waker_reference = Arc::new(Mutex::new(None as Option<Waker>));
|
||||
|
||||
app_src.set_callbacks(
|
||||
AppSrcCallbacks::new()
|
||||
.need_data({
|
||||
let waker_reference = Arc::clone(&waker_reference);
|
||||
|
||||
move |_, _| {
|
||||
if let Some(waker) = waker_reference.lock().unwrap().take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
})
|
||||
.build(),
|
||||
);
|
||||
|
||||
Self {
|
||||
app_src,
|
||||
waker_reference,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AppSrcSink {
|
||||
fn drop(&mut self) {
|
||||
// This is not thread-safe before 1.16.3, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/merge_requests/570
|
||||
if gst::version() >= (1, 16, 3, 0) {
|
||||
self.app_src.set_callbacks(AppSrcCallbacks::new().build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sink<gst::Sample> for AppSrcSink {
|
||||
type Error = gst::FlowError;
|
||||
|
||||
fn poll_ready(self: Pin<&mut Self>, context: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
let mut waker = self.waker_reference.lock().unwrap();
|
||||
|
||||
let current_level_bytes = self.app_src.get_current_level_bytes();
|
||||
let max_bytes = self.app_src.get_max_bytes();
|
||||
|
||||
if current_level_bytes >= max_bytes && max_bytes != 0 {
|
||||
waker.replace(context.waker().to_owned());
|
||||
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn start_send(self: Pin<&mut Self>, sample: gst::Sample) -> Result<(), Self::Error> {
|
||||
self.app_src.push_sample(&sample)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_close(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.app_src.end_of_stream()?;
|
||||
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures_util::{sink::SinkExt, stream::StreamExt};
|
||||
use gst::prelude::*;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
#[test]
|
||||
fn test_app_src_sink() {
|
||||
gst::init().unwrap();
|
||||
|
||||
let appsrc = gst::ElementFactory::make("appsrc", None).unwrap();
|
||||
let fakesink = gst::ElementFactory::make("fakesink", None).unwrap();
|
||||
|
||||
fakesink.set_property("signal-handoffs", &true).unwrap();
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
pipeline.add(&appsrc).unwrap();
|
||||
pipeline.add(&fakesink).unwrap();
|
||||
|
||||
appsrc.link(&fakesink).unwrap();
|
||||
|
||||
let mut bus_stream = pipeline.get_bus().unwrap().stream();
|
||||
let mut app_src_sink = appsrc.dynamic_cast::<AppSrc>().unwrap().sink();
|
||||
|
||||
let sample_quantity = 5;
|
||||
|
||||
let samples = (0..sample_quantity)
|
||||
.map(|_| gst::Sample::new().buffer(&gst::Buffer::new()).build())
|
||||
.collect::<Vec<gst::Sample>>();
|
||||
|
||||
let mut sample_stream = futures_util::stream::iter(samples).map(Ok);
|
||||
|
||||
let handoff_count_reference = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
fakesink
|
||||
.connect("handoff", false, {
|
||||
let handoff_count_reference = Arc::clone(&handoff_count_reference);
|
||||
|
||||
move |_| {
|
||||
handoff_count_reference.fetch_add(1, Ordering::AcqRel);
|
||||
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
pipeline.set_state(gst::State::Playing).unwrap();
|
||||
|
||||
futures_executor::block_on(app_src_sink.send_all(&mut sample_stream)).unwrap();
|
||||
futures_executor::block_on(app_src_sink.close()).unwrap();
|
||||
|
||||
while let Some(message) = futures_executor::block_on(bus_stream.next()) {
|
||||
match message.view() {
|
||||
gst::MessageView::Eos(_) => break,
|
||||
gst::MessageView::Error(_) => unreachable!(),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.set_state(gst::State::Null).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
handoff_count_reference.load(Ordering::Acquire),
|
||||
sample_quantity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
extern crate libc;
|
||||
|
||||
extern crate futures_core;
|
||||
extern crate futures_sink;
|
||||
extern crate glib_sys;
|
||||
extern crate gobject_sys;
|
||||
extern crate gstreamer as gst;
|
||||
|
@ -15,9 +17,18 @@ extern crate gstreamer_app_sys as gst_app_sys;
|
|||
extern crate gstreamer_base as gst_base;
|
||||
extern crate gstreamer_sys as gst_sys;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[macro_use]
|
||||
extern crate glib;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate futures_util;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate futures_executor;
|
||||
|
||||
macro_rules! skip_assert_initialized {
|
||||
() => {};
|
||||
}
|
||||
|
@ -28,10 +39,11 @@ macro_rules! skip_assert_initialized {
|
|||
mod auto;
|
||||
pub use auto::*;
|
||||
|
||||
mod app_sink;
|
||||
mod app_src;
|
||||
pub use app_sink::*;
|
||||
pub use app_src::*;
|
||||
pub mod app_sink;
|
||||
pub use app_sink::AppSinkCallbacks;
|
||||
|
||||
pub mod app_src;
|
||||
pub use app_src::AppSrcCallbacks;
|
||||
|
||||
// Re-export all the traits in a prelude module, so that applications
|
||||
// can always "use gst::prelude::*" without getting conflicts
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-audio"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Audio library"
|
||||
|
@ -15,14 +15,14 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
libc = "0.2"
|
||||
bitflags = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-audio-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-base = { path = "../gstreamer-base" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-audio-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-base = { version = "0.15", path = "../gstreamer-base" }
|
||||
array-init = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -37,46 +37,48 @@ impl AudioStreamAlign {
|
|||
}
|
||||
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
pub fn get_alignment_threshold(&mut self) -> gst::ClockTime {
|
||||
pub fn get_alignment_threshold(&self) -> gst::ClockTime {
|
||||
unsafe {
|
||||
from_glib(
|
||||
gst_audio_sys::gst_audio_stream_align_get_alignment_threshold(
|
||||
self.to_glib_none_mut().0,
|
||||
),
|
||||
gst_audio_sys::gst_audio_stream_align_get_alignment_threshold(mut_override(
|
||||
self.to_glib_none().0,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
pub fn get_discont_wait(&mut self) -> gst::ClockTime {
|
||||
pub fn get_discont_wait(&self) -> gst::ClockTime {
|
||||
unsafe {
|
||||
from_glib(gst_audio_sys::gst_audio_stream_align_get_discont_wait(
|
||||
self.to_glib_none_mut().0,
|
||||
mut_override(self.to_glib_none().0),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
pub fn get_rate(&mut self) -> i32 {
|
||||
unsafe { gst_audio_sys::gst_audio_stream_align_get_rate(self.to_glib_none_mut().0) }
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
pub fn get_samples_since_discont(&mut self) -> u64 {
|
||||
pub fn get_rate(&self) -> i32 {
|
||||
unsafe {
|
||||
gst_audio_sys::gst_audio_stream_align_get_samples_since_discont(
|
||||
self.to_glib_none_mut().0,
|
||||
)
|
||||
gst_audio_sys::gst_audio_stream_align_get_rate(mut_override(self.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
pub fn get_timestamp_at_discont(&mut self) -> gst::ClockTime {
|
||||
pub fn get_samples_since_discont(&self) -> u64 {
|
||||
unsafe {
|
||||
gst_audio_sys::gst_audio_stream_align_get_samples_since_discont(mut_override(
|
||||
self.to_glib_none().0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
pub fn get_timestamp_at_discont(&self) -> gst::ClockTime {
|
||||
unsafe {
|
||||
from_glib(
|
||||
gst_audio_sys::gst_audio_stream_align_get_timestamp_at_discont(
|
||||
self.to_glib_none_mut().0,
|
||||
),
|
||||
gst_audio_sys::gst_audio_stream_align_get_timestamp_at_discont(mut_override(
|
||||
self.to_glib_none().0,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-base"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Base library"
|
||||
|
@ -15,12 +15,12 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
libc = "0.2"
|
||||
bitflags = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -21,7 +21,7 @@ impl<O: IsA<AggregatorPad>> AggregatorPadExtManual for O {
|
|||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let ptr: &gst_base_sys::GstAggregatorPad = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&ptr.parent.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&ptr.parent.object.lock);
|
||||
from_glib_none(&ptr.segment as *const gst_sys::GstSegment)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ impl<O: IsA<BaseSink>> BaseSinkExtManual for O {
|
|||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let sink: &gst_base_sys::GstBaseSink = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&sink.element.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&sink.element.object.lock);
|
||||
from_glib_none(&sink.segment as *const _)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ impl<O: IsA<BaseSrc>> BaseSrcExtManual for O {
|
|||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let src: &gst_base_sys::GstBaseSrc = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&src.element.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&src.element.object.lock);
|
||||
from_glib_none(&src.segment as *const _)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ impl<O: IsA<BaseTransform>> BaseTransformExtManual for O {
|
|||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let trans: &gst_base_sys::GstBaseTransform = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&trans.element.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&trans.element.object.lock);
|
||||
from_glib_none(&trans.segment as *const _)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ impl UniqueFlowCombiner {
|
|||
self.0.add_pad(pad);
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use gst;
|
|||
use gst::subclass::prelude::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use BaseTransform;
|
||||
use BaseTransformClass;
|
||||
|
@ -101,6 +102,14 @@ pub trait BaseTransformImpl: BaseTransformImplExt + ElementImpl + Send + Sync +
|
|||
self.parent_src_event(element, event)
|
||||
}
|
||||
|
||||
fn prepare_output_buffer(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
inbuf: &gst::BufferRef,
|
||||
) -> Result<PreparedOutputBuffer, gst::FlowError> {
|
||||
self.parent_prepare_output_buffer(element, inbuf)
|
||||
}
|
||||
|
||||
fn transform(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
|
@ -125,6 +134,42 @@ pub trait BaseTransformImpl: BaseTransformImplExt + ElementImpl + Send + Sync +
|
|||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||
self.parent_transform_ip_passthrough(element, buf)
|
||||
}
|
||||
|
||||
fn copy_metadata(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
inbuf: &gst::BufferRef,
|
||||
outbuf: &mut gst::BufferRef,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.parent_copy_metadata(element, inbuf, outbuf)
|
||||
}
|
||||
|
||||
fn transform_meta<'a>(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
outbuf: &mut gst::BufferRef,
|
||||
meta: gst::MetaRef<'a, gst::Meta>,
|
||||
inbuf: &'a gst::BufferRef,
|
||||
) -> bool {
|
||||
self.parent_transform_meta(element, outbuf, meta, inbuf)
|
||||
}
|
||||
|
||||
fn before_transform(&self, element: &BaseTransform, inbuf: &gst::BufferRef) {
|
||||
self.parent_before_transform(element, inbuf);
|
||||
}
|
||||
|
||||
fn submit_input_buffer(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
is_discont: bool,
|
||||
inbuf: gst::Buffer,
|
||||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||
self.parent_submit_input_buffer(element, is_discont, inbuf)
|
||||
}
|
||||
|
||||
fn generate_output(&self, element: &BaseTransform) -> Result<GeneratedOutput, gst::FlowError> {
|
||||
self.parent_generate_output(element)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BaseTransformImplExt {
|
||||
|
@ -184,6 +229,12 @@ pub trait BaseTransformImplExt {
|
|||
|
||||
fn parent_src_event(&self, element: &BaseTransform, event: gst::Event) -> bool;
|
||||
|
||||
fn parent_prepare_output_buffer(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
inbuf: &gst::BufferRef,
|
||||
) -> Result<PreparedOutputBuffer, gst::FlowError>;
|
||||
|
||||
fn parent_transform(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
|
@ -202,6 +253,45 @@ pub trait BaseTransformImplExt {
|
|||
element: &BaseTransform,
|
||||
buf: &gst::Buffer,
|
||||
) -> Result<gst::FlowSuccess, gst::FlowError>;
|
||||
|
||||
fn parent_copy_metadata(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
inbuf: &gst::BufferRef,
|
||||
outbuf: &mut gst::BufferRef,
|
||||
) -> Result<(), gst::LoggableError>;
|
||||
|
||||
fn parent_transform_meta<'a>(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
outbuf: &mut gst::BufferRef,
|
||||
meta: gst::MetaRef<'a, gst::Meta>,
|
||||
inbuf: &'a gst::BufferRef,
|
||||
) -> bool;
|
||||
|
||||
fn parent_before_transform(&self, element: &BaseTransform, inbuf: &gst::BufferRef);
|
||||
|
||||
fn parent_submit_input_buffer(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
is_discont: bool,
|
||||
inbuf: gst::Buffer,
|
||||
) -> Result<gst::FlowSuccess, gst::FlowError>;
|
||||
|
||||
fn parent_generate_output(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
) -> Result<GeneratedOutput, gst::FlowError>;
|
||||
|
||||
fn take_queued_buffer(&self) -> Option<gst::Buffer>
|
||||
where
|
||||
Self: ObjectSubclass,
|
||||
<Self as ObjectSubclass>::ParentType: IsA<BaseTransform>;
|
||||
|
||||
fn get_queued_buffer(&self) -> Option<gst::Buffer>
|
||||
where
|
||||
Self: ObjectSubclass,
|
||||
<Self as ObjectSubclass>::ParentType: IsA<BaseTransform>;
|
||||
}
|
||||
|
||||
impl<T: BaseTransformImpl + ObjectImpl> BaseTransformImplExt for T {
|
||||
|
@ -458,6 +548,41 @@ impl<T: BaseTransformImpl + ObjectImpl> BaseTransformImplExt for T {
|
|||
}
|
||||
}
|
||||
|
||||
fn parent_prepare_output_buffer(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
inbuf: &gst::BufferRef,
|
||||
) -> Result<PreparedOutputBuffer, gst::FlowError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseTransformClass;
|
||||
(*parent_class)
|
||||
.prepare_output_buffer
|
||||
.map(|f| {
|
||||
let mut outbuf: *mut gst_sys::GstBuffer = ptr::null_mut();
|
||||
// FIXME: Wrong signature in FFI
|
||||
let res = from_glib(f(
|
||||
element.to_glib_none().0,
|
||||
inbuf.as_ptr() as *mut gst_sys::GstBuffer,
|
||||
(&mut outbuf) as *mut *mut gst_sys::GstBuffer as *mut gst_sys::GstBuffer,
|
||||
));
|
||||
|
||||
match gst::FlowReturn::into_result(res) {
|
||||
Err(err) => Err(err),
|
||||
Ok(_) => {
|
||||
if outbuf == inbuf.as_ptr() as *mut _ {
|
||||
Ok(PreparedOutputBuffer::InputBuffer)
|
||||
} else {
|
||||
Ok(PreparedOutputBuffer::Buffer(from_glib_full(outbuf)))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap_or(Err(gst::FlowError::NotSupported))
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_transform(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
|
@ -547,6 +672,149 @@ impl<T: BaseTransformImpl + ObjectImpl> BaseTransformImplExt for T {
|
|||
gst::FlowReturn::from_glib(f(element.to_glib_none().0, buf as *mut _)).into_result()
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_copy_metadata(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
inbuf: &gst::BufferRef,
|
||||
outbuf: &mut gst::BufferRef,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseTransformClass;
|
||||
if let Some(ref f) = (*parent_class).copy_metadata {
|
||||
gst_result_from_gboolean!(
|
||||
f(
|
||||
element.to_glib_none().0,
|
||||
inbuf.as_ptr() as *mut _,
|
||||
outbuf.as_mut_ptr()
|
||||
),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `copy_metadata` failed"
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_transform_meta<'a>(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
outbuf: &mut gst::BufferRef,
|
||||
meta: gst::MetaRef<'a, gst::Meta>,
|
||||
inbuf: &'a gst::BufferRef,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseTransformClass;
|
||||
(*parent_class)
|
||||
.transform_meta
|
||||
.map(|f| {
|
||||
from_glib(f(
|
||||
element.to_glib_none().0,
|
||||
outbuf.as_mut_ptr(),
|
||||
meta.as_ptr() as *mut _,
|
||||
inbuf.as_ptr() as *mut _,
|
||||
))
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_before_transform(&self, element: &BaseTransform, inbuf: &gst::BufferRef) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseTransformClass;
|
||||
if let Some(ref f) = (*parent_class).before_transform {
|
||||
f(element.to_glib_none().0, inbuf.as_ptr() as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_submit_input_buffer(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
is_discont: bool,
|
||||
inbuf: gst::Buffer,
|
||||
) -> Result<gst::FlowSuccess, gst::FlowError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseTransformClass;
|
||||
let f = (*parent_class)
|
||||
.submit_input_buffer
|
||||
.expect("Missing parent function `submit_input_buffer`");
|
||||
|
||||
gst::FlowReturn::from_glib(f(
|
||||
element.to_glib_none().0,
|
||||
is_discont.to_glib(),
|
||||
inbuf.into_ptr(),
|
||||
))
|
||||
.into_result()
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_generate_output(
|
||||
&self,
|
||||
element: &BaseTransform,
|
||||
) -> Result<GeneratedOutput, gst::FlowError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseTransformClass;
|
||||
let f = (*parent_class)
|
||||
.generate_output
|
||||
.expect("Missing parent function `generate_output`");
|
||||
|
||||
let mut outbuf = ptr::null_mut();
|
||||
gst::FlowReturn::from_glib(f(element.to_glib_none().0, &mut outbuf))
|
||||
.into_result()
|
||||
.map(|res| {
|
||||
if res == ::BASE_TRANSFORM_FLOW_DROPPED {
|
||||
GeneratedOutput::Dropped
|
||||
} else if res != gst::FlowSuccess::Ok || outbuf.is_null() {
|
||||
GeneratedOutput::NoOutput
|
||||
} else {
|
||||
GeneratedOutput::Buffer(from_glib_full(outbuf))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn take_queued_buffer(&self) -> Option<gst::Buffer>
|
||||
where
|
||||
Self: ObjectSubclass,
|
||||
<Self as ObjectSubclass>::ParentType: IsA<BaseTransform>,
|
||||
{
|
||||
unsafe {
|
||||
let element = self.get_instance();
|
||||
let ptr: *mut gst_base_sys::GstBaseTransform = element.to_glib_none().0 as *mut _;
|
||||
let sinkpad: gst::Pad = from_glib_borrow((*ptr).sinkpad);
|
||||
let _stream_lock = sinkpad.stream_lock();
|
||||
let buffer = (*ptr).queued_buf;
|
||||
(*ptr).queued_buf = ptr::null_mut();
|
||||
from_glib_full(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_queued_buffer(&self) -> Option<gst::Buffer>
|
||||
where
|
||||
Self: ObjectSubclass,
|
||||
<Self as ObjectSubclass>::ParentType: IsA<BaseTransform>,
|
||||
{
|
||||
unsafe {
|
||||
let element = self.get_instance();
|
||||
let ptr: *mut gst_base_sys::GstBaseTransform = element.to_glib_none().0 as *mut _;
|
||||
let sinkpad: gst::Pad = from_glib_borrow((*ptr).sinkpad);
|
||||
let _stream_lock = sinkpad.stream_lock();
|
||||
let buffer = (*ptr).queued_buf;
|
||||
from_glib_none(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -573,8 +841,14 @@ where
|
|||
klass.query = Some(base_transform_query::<T>);
|
||||
klass.transform_size = Some(base_transform_transform_size::<T>);
|
||||
klass.get_unit_size = Some(base_transform_get_unit_size::<T>);
|
||||
klass.prepare_output_buffer = Some(base_transform_prepare_output_buffer::<T>);
|
||||
klass.sink_event = Some(base_transform_sink_event::<T>);
|
||||
klass.src_event = Some(base_transform_src_event::<T>);
|
||||
klass.transform_meta = Some(base_transform_transform_meta::<T>);
|
||||
klass.copy_metadata = Some(base_transform_copy_metadata::<T>);
|
||||
klass.before_transform = Some(base_transform_before_transform::<T>);
|
||||
klass.submit_input_buffer = Some(base_transform_submit_input_buffer::<T>);
|
||||
klass.generate_output = Some(base_transform_generate_output::<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -618,6 +892,19 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GeneratedOutput {
|
||||
Buffer(gst::Buffer),
|
||||
NoOutput,
|
||||
Dropped,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PreparedOutputBuffer {
|
||||
Buffer(gst::Buffer),
|
||||
InputBuffer,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_start<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
) -> glib_sys::gboolean
|
||||
|
@ -848,6 +1135,38 @@ where
|
|||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_prepare_output_buffer<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
inbuf: *mut gst_sys::GstBuffer,
|
||||
outbuf: *mut gst_sys::GstBuffer,
|
||||
) -> gst_sys::GstFlowReturn
|
||||
where
|
||||
T: BaseTransformImpl,
|
||||
T::Instance: PanicPoison,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: BaseTransform = from_glib_borrow(ptr);
|
||||
|
||||
// FIXME: Wrong signature in FFI
|
||||
let outbuf = outbuf as *mut *mut gst_sys::GstBuffer;
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, {
|
||||
match imp.prepare_output_buffer(&wrap, gst::BufferRef::from_ptr(inbuf)) {
|
||||
Ok(PreparedOutputBuffer::InputBuffer) => {
|
||||
*outbuf = inbuf;
|
||||
gst::FlowReturn::Ok
|
||||
}
|
||||
Ok(PreparedOutputBuffer::Buffer(buf)) => {
|
||||
*outbuf = buf.into_ptr();
|
||||
gst::FlowReturn::Ok
|
||||
}
|
||||
Err(err) => err.into(),
|
||||
}
|
||||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_sink_event<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
event: *mut gst_sys::GstEvent,
|
||||
|
@ -934,3 +1253,133 @@ where
|
|||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_transform_meta<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
outbuf: *mut gst_sys::GstBuffer,
|
||||
meta: *mut gst_sys::GstMeta,
|
||||
inbuf: *mut gst_sys::GstBuffer,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: BaseTransformImpl,
|
||||
T::Instance: PanicPoison,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: BaseTransform = from_glib_borrow(ptr);
|
||||
|
||||
let inbuf = gst::BufferRef::from_ptr(inbuf);
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), false, {
|
||||
imp.transform_meta(
|
||||
&wrap,
|
||||
gst::BufferRef::from_mut_ptr(outbuf),
|
||||
gst::Meta::from_ptr(inbuf, meta),
|
||||
inbuf,
|
||||
)
|
||||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_copy_metadata<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
inbuf: *mut gst_sys::GstBuffer,
|
||||
outbuf: *mut gst_sys::GstBuffer,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: BaseTransformImpl,
|
||||
T::Instance: PanicPoison,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: BaseTransform = from_glib_borrow(ptr);
|
||||
|
||||
if gst_sys::gst_mini_object_is_writable(outbuf as *mut _) == glib_sys::GFALSE {
|
||||
gst_warning!(
|
||||
gst::CAT_RUST,
|
||||
obj: &wrap,
|
||||
"buffer {:?} not writable",
|
||||
outbuf
|
||||
);
|
||||
return glib_sys::GFALSE;
|
||||
}
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), true, {
|
||||
match imp.copy_metadata(
|
||||
&wrap,
|
||||
gst::BufferRef::from_ptr(inbuf),
|
||||
gst::BufferRef::from_mut_ptr(outbuf),
|
||||
) {
|
||||
Ok(_) => true,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_before_transform<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
inbuf: *mut gst_sys::GstBuffer,
|
||||
) where
|
||||
T: BaseTransformImpl,
|
||||
T::Instance: PanicPoison,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: BaseTransform = from_glib_borrow(ptr);
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), (), {
|
||||
imp.before_transform(&wrap, gst::BufferRef::from_ptr(inbuf));
|
||||
})
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_submit_input_buffer<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
is_discont: glib_sys::gboolean,
|
||||
buf: *mut gst_sys::GstBuffer,
|
||||
) -> gst_sys::GstFlowReturn
|
||||
where
|
||||
T: BaseTransformImpl,
|
||||
T::Instance: PanicPoison,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: BaseTransform = from_glib_borrow(ptr);
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, {
|
||||
imp.submit_input_buffer(&wrap, from_glib(is_discont), from_glib_full(buf))
|
||||
.into()
|
||||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn base_transform_generate_output<T: ObjectSubclass>(
|
||||
ptr: *mut gst_base_sys::GstBaseTransform,
|
||||
buf: *mut *mut gst_sys::GstBuffer,
|
||||
) -> gst_sys::GstFlowReturn
|
||||
where
|
||||
T: BaseTransformImpl,
|
||||
T::Instance: PanicPoison,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: BaseTransform = from_glib_borrow(ptr);
|
||||
|
||||
*buf = ptr::null_mut();
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, {
|
||||
match imp.generate_output(&wrap) {
|
||||
Ok(GeneratedOutput::Dropped) => ::BASE_TRANSFORM_FLOW_DROPPED.into(),
|
||||
Ok(GeneratedOutput::NoOutput) => gst::FlowReturn::Ok,
|
||||
Ok(GeneratedOutput::Buffer(outbuf)) => {
|
||||
*buf = outbuf.into_ptr();
|
||||
gst::FlowReturn::Ok
|
||||
}
|
||||
Err(err) => err.into(),
|
||||
}
|
||||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
use glib::translate::mut_override;
|
||||
use glib_sys;
|
||||
|
||||
#[must_use = "if unused the Mutex will immediately unlock"]
|
||||
pub struct MutexGuard<'a>(&'a glib_sys::GMutex);
|
||||
|
||||
impl<'a> MutexGuard<'a> {
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-check"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Check library"
|
||||
|
@ -14,12 +14,12 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-check-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-check-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -730,7 +730,7 @@ impl Harness {
|
|||
None
|
||||
} else {
|
||||
Some(Ref(
|
||||
Some(Harness(
|
||||
mem::ManuallyDrop::new(Harness(
|
||||
ptr::NonNull::new_unchecked(sink_harness),
|
||||
PhantomData,
|
||||
)),
|
||||
|
@ -747,7 +747,7 @@ impl Harness {
|
|||
None
|
||||
} else {
|
||||
Some(Ref(
|
||||
Some(Harness(
|
||||
mem::ManuallyDrop::new(Harness(
|
||||
ptr::NonNull::new_unchecked(src_harness),
|
||||
PhantomData,
|
||||
)),
|
||||
|
@ -764,7 +764,7 @@ impl Harness {
|
|||
None
|
||||
} else {
|
||||
Some(RefMut(
|
||||
Some(Harness(
|
||||
mem::ManuallyDrop::new(Harness(
|
||||
ptr::NonNull::new_unchecked(sink_harness),
|
||||
PhantomData,
|
||||
)),
|
||||
|
@ -781,7 +781,7 @@ impl Harness {
|
|||
None
|
||||
} else {
|
||||
Some(RefMut(
|
||||
Some(Harness(
|
||||
mem::ManuallyDrop::new(Harness(
|
||||
ptr::NonNull::new_unchecked(src_harness),
|
||||
PhantomData,
|
||||
)),
|
||||
|
@ -793,44 +793,30 @@ impl Harness {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Ref<'a>(Option<Harness>, PhantomData<&'a Harness>);
|
||||
pub struct Ref<'a>(mem::ManuallyDrop<Harness>, PhantomData<&'a Harness>);
|
||||
|
||||
impl<'a> ops::Deref for Ref<'a> {
|
||||
type Target = Harness;
|
||||
|
||||
fn deref(&self) -> &Harness {
|
||||
self.0.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Ref<'a> {
|
||||
fn drop(&mut self) {
|
||||
// We only really borrow
|
||||
mem::forget(self.0.take())
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RefMut<'a>(Option<Harness>, PhantomData<&'a mut Harness>);
|
||||
pub struct RefMut<'a>(mem::ManuallyDrop<Harness>, PhantomData<&'a mut Harness>);
|
||||
|
||||
impl<'a> ops::Deref for RefMut<'a> {
|
||||
type Target = Harness;
|
||||
|
||||
fn deref(&self) -> &Harness {
|
||||
self.0.as_ref().unwrap()
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::DerefMut for RefMut<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Harness {
|
||||
self.0.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for RefMut<'a> {
|
||||
fn drop(&mut self) {
|
||||
// We only really borrow
|
||||
mem::forget(self.0.take())
|
||||
&mut *self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-editing-services"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Thibault Saunier <tsaunier@igalia.com>", "Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Editing Services"
|
||||
|
@ -15,16 +15,16 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
libc = "0.2"
|
||||
bitflags = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gio-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-editing-services-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"]}
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gio = { git = "https://github.com/gtk-rs/gio" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-base = { path = "../gstreamer-base" }
|
||||
gstreamer-pbutils = { path = "../gstreamer-pbutils" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gio-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-editing-services-sys = { version = "0.8", features = ["v1_8"]}
|
||||
glib = { version = "0.9" }
|
||||
gio = { version = "0.8" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-base = { version = "0.15", path = "../gstreamer-base" }
|
||||
gstreamer-pbutils = { version = "0.15", path = "../gstreamer-pbutils" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-gl"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>",
|
||||
"Víctor M. Jáquez L. <vjaquez@igalia.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
|
@ -18,15 +18,15 @@ bitflags = "1.0"
|
|||
byteorder = "1"
|
||||
libc = "0.2"
|
||||
lazy_static = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_14"] }
|
||||
gstreamer-video-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_14"] }
|
||||
gstreamer-gl-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer", features = ["v1_14"] }
|
||||
gstreamer-base = { path = "../gstreamer-base", features = ["v1_14"] }
|
||||
gstreamer-video = { path = "../gstreamer-video", features = ["v1_14"] }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_14"] }
|
||||
gstreamer-video-sys = { version = "0.8", features = ["v1_14"] }
|
||||
gstreamer-gl-sys = { version = "0.8" }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer", features = ["v1_14"] }
|
||||
gstreamer-base = { version = "0.15", path = "../gstreamer-base", features = ["v1_14"] }
|
||||
gstreamer-video = { version = "0.15", path = "../gstreamer-video", features = ["v1_14"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-net"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Net library"
|
||||
|
@ -13,13 +13,13 @@ keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-net-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gio = { git = "https://github.com/gtk-rs/gio" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-net-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gio = { version = "0.8" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-pbutils"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Base Utils library"
|
||||
|
@ -15,12 +15,12 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-pbutils-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-pbutils-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -488,19 +488,19 @@ mod tests {
|
|||
use auto::EncodingVideoProfile;
|
||||
use gst;
|
||||
|
||||
const AUDIO_PROFILE_NAME: &'static str = "audio-profile";
|
||||
const AUDIO_PROFILE_DESCRIPTION: &'static str = "audio-profile-description";
|
||||
const PRESET: &'static str = "preset";
|
||||
const PRESET_NAME: &'static str = "preset-name";
|
||||
const AUDIO_PROFILE_NAME: &str = "audio-profile";
|
||||
const AUDIO_PROFILE_DESCRIPTION: &str = "audio-profile-description";
|
||||
const PRESET: &str = "preset";
|
||||
const PRESET_NAME: &str = "preset-name";
|
||||
const PRESENCE: u32 = 5;
|
||||
const ALLOW_DYNAMIC_OUTPUT: bool = false;
|
||||
const ENABLED: bool = false;
|
||||
|
||||
const VIDEO_PROFILE_NAME: &'static str = "video-profile";
|
||||
const VIDEO_PROFILE_DESCRIPTION: &'static str = "video-profile-description";
|
||||
const VIDEO_PROFILE_NAME: &str = "video-profile";
|
||||
const VIDEO_PROFILE_DESCRIPTION: &str = "video-profile-description";
|
||||
|
||||
const CONTAINER_PROFILE_NAME: &'static str = "container-profile";
|
||||
const CONTAINER_PROFILE_DESCRIPTION: &'static str = "container-profile-description";
|
||||
const CONTAINER_PROFILE_NAME: &str = "container-profile";
|
||||
const CONTAINER_PROFILE_DESCRIPTION: &str = "container-profile-description";
|
||||
|
||||
// Video profile exclusive attributes
|
||||
const PASS: u32 = 8;
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-player"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Player library"
|
||||
|
@ -15,13 +15,13 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_12"] }
|
||||
gstreamer-player-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer", features = ["v1_12"] }
|
||||
gstreamer-video = { path = "../gstreamer-video", features = ["v1_12"] }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_12"] }
|
||||
gstreamer-player-sys = { version = "0.8" }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer", features = ["v1_12"] }
|
||||
gstreamer-video = { version = "0.15", path = "../gstreamer-video", features = ["v1_12"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -14,7 +14,7 @@ use gst_sys;
|
|||
use std::mem;
|
||||
use std::ops;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PlayerConfig(gst::Structure);
|
||||
|
||||
impl ops::Deref for PlayerConfig {
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-rtp"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Mathieu Duponchelle <mathieu@centricular.com>", "Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Rtp library"
|
||||
|
@ -15,12 +15,12 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
lazy_static = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-rtp-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-rtp-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
version = "0.1"
|
||||
|
|
196
gstreamer-rtp/README.md
Normal file
196
gstreamer-rtp/README.md
Normal file
|
@ -0,0 +1,196 @@
|
|||
# gstreamer-rs [![crates.io](https://img.shields.io/crates/v/gstreamer-rtp.svg)](https://crates.io/crates/gstreamer-rtp) [![pipeline status](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/badges/master/pipeline.svg)](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/commits/master)
|
||||
|
||||
[GStreamer](https://gstreamer.freedesktop.org/) bindings for Rust.
|
||||
Documentation can be found [here](https://slomo.pages.freedesktop.org/rustdocs/gstreamer/gstreamer_rtp/).
|
||||
|
||||
These bindings are providing a safe API that can be used to interface with
|
||||
GStreamer, e.g. for writing GStreamer-based applications and GStreamer plugins.
|
||||
|
||||
The bindings are mostly autogenerated with [gir](https://github.com/gtk-rs/gir/)
|
||||
based on the [GObject-Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection/)
|
||||
API metadata provided by the GStreamer project.
|
||||
|
||||
## Table of Contents
|
||||
1. [Installation](#installation)
|
||||
1. [Linux/BSDs](#installation-linux)
|
||||
1. [macOS](#installation-macos)
|
||||
1. [Windows](#installation-windows)
|
||||
1. [Getting Started](#getting-started)
|
||||
1. [License](#license)
|
||||
1. [Contribution](#contribution)
|
||||
|
||||
<a name="installation"/>
|
||||
|
||||
## Installation
|
||||
|
||||
To build the GStreamer bindings or anything depending on them, you need to
|
||||
have at least GStreamer 1.8 and gst-plugins-base 1.8 installed. In addition,
|
||||
some of the examples/tutorials require various GStreamer plugins to be
|
||||
available, which can be found in gst-plugins-base, gst-plugins-good,
|
||||
gst-plugins-bad, gst-plugins-ugly and/or gst-libav.
|
||||
|
||||
<a name="installation-linux"/>
|
||||
|
||||
### Linux/BSDs
|
||||
|
||||
You need to install the above mentioned packages with your distributions
|
||||
package manager, or build them from source.
|
||||
|
||||
On Debian/Ubuntu they can be installed with
|
||||
|
||||
```
|
||||
$ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-libav libgstrtspserver-1.0-dev
|
||||
```
|
||||
|
||||
The minimum required version of the above libraries is >= 1.8. If you
|
||||
build the gstreamer-player sub-crate, or any of the examples that
|
||||
depend on gstreamer-player, you must ensure that in addition to the
|
||||
above packages, `libgstreamer-plugins-bad1.0-dev` is installed and
|
||||
that the version is >= 1.12. See the `Cargo.toml` files for the full
|
||||
details,
|
||||
|
||||
```
|
||||
# Only if you wish to install gstreamer-player, make sure the version
|
||||
# of this package is >= 1.12.
|
||||
$ apt-get install libgstreamer-plugins-bad1.0-dev
|
||||
```
|
||||
|
||||
Package names on other distributions should be similar.
|
||||
Please submit a pull request with instructions for yours.
|
||||
|
||||
<a name="installation-macos"/>
|
||||
|
||||
### macOS
|
||||
|
||||
You can install GStreamer and the plugins via [Homebrew](https://brew.sh/) or
|
||||
by installing the [binaries](https://gstreamer.freedesktop.org/data/pkg/osx/)
|
||||
provided by the GStreamer project.
|
||||
|
||||
#### Homebrew
|
||||
|
||||
Homebrew only installs various plugins if explicitly enabled, so some extra
|
||||
`--with-*` flags may be required.
|
||||
|
||||
```
|
||||
$ brew install gstreamer gst-plugins-base gst-plugins-good \
|
||||
gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server \
|
||||
gst-editing-services --with-orc --with-libogg --with-opus \
|
||||
--with-pango --with-theora --with-libvorbis --with-libvpx \
|
||||
--enable-gtk3
|
||||
```
|
||||
|
||||
If you wish to install the gstreamer-player sub-crate, make sure the
|
||||
version of these libraries is >= 1.12. Otherwise, a version >= 1.8 is
|
||||
sufficient.
|
||||
|
||||
#### GStreamer Binaries
|
||||
|
||||
You need to download the *two* `.pkg` files from the GStreamer website and
|
||||
install them, e.g. `gstreamer-1.0-1.12.3-x86_64.pkg` and
|
||||
`gstreamer-1.0-devel-1.12.3-x86_64.pkg`.
|
||||
|
||||
After installation, you also need to install `pkg-config` (e.g. via Homebrew)
|
||||
and set the `PKG_CONFIG_PATH` environment variable
|
||||
|
||||
```
|
||||
$ export PKG_CONFIG_PATH="/Library/Frameworks/GStreamer.framework/Versions/Current/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
|
||||
```
|
||||
|
||||
<a name="installation-windows"/>
|
||||
|
||||
### Windows
|
||||
|
||||
You can install GStreamer and the plugins via [MSYS2](http://www.msys2.org/)
|
||||
with `pacman` or by installing the
|
||||
[binaries](https://gstreamer.freedesktop.org/data/pkg/windows/) provided by
|
||||
the GStreamer project.
|
||||
|
||||
#### MSYS2 / pacman
|
||||
|
||||
```
|
||||
$ pacman -S pkg-config mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base \
|
||||
mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad \
|
||||
mingw-w64-x86_64-gst-plugins-ugly mingw-w64-x86_64-gst-libav \
|
||||
mingw-w64-x86_64-gst-rtsp-server
|
||||
```
|
||||
|
||||
If you wish to install the gstreamer-player sub-crate, make sure the
|
||||
version of these libraries is >= 1.12. Otherwise, a version >= 1.8 is
|
||||
sufficient.
|
||||
|
||||
#### GStreamer Binaries
|
||||
|
||||
You need to download the *two* `.msi` files for your platform from the
|
||||
GStreamer website and install them, e.g. `gstreamer-1.0-x86_64-1.12.3.msi` and
|
||||
`gstreamer-1.0-devel-x86_64-1.12.3.msi`.
|
||||
|
||||
After installation, you also need to install `pkg-config` (e.g. via MSYS2 or
|
||||
from [here](https://sourceforge.net/projects/pkgconfiglite/))
|
||||
and set the `PKG_CONFIG_PATH` environment variable
|
||||
|
||||
```
|
||||
$ export PKG_CONFIG_PATH="c:\\gstreamer\\1.0\\x86_64\\lib\\pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
|
||||
```
|
||||
|
||||
<a name="getting-started"/>
|
||||
|
||||
## Getting Started
|
||||
|
||||
The API reference can be found
|
||||
[here](https://slomo.pages.freedesktop.org/rustdocs/gstreamer/gstreamer/), however it is
|
||||
only the Rust API reference and does not explain any of the concepts.
|
||||
|
||||
For getting started with GStreamer development, the best would be to follow
|
||||
the [documentation](https://gstreamer.freedesktop.org/documentation/) on the
|
||||
GStreamer website, especially the [Application Development
|
||||
Manual](https://gstreamer.freedesktop.org/documentation/application-development/).
|
||||
While being C-centric, it explains all the fundamental concepts of GStreamer
|
||||
and the code examples should be relatively easily translatable to Rust. The
|
||||
API is basically the same, function/struct names are the same and everything
|
||||
is only more convenient (hopefully) and safer.
|
||||
|
||||
In addition there are
|
||||
[tutorials](https://gstreamer.freedesktop.org/documentation/tutorials/) on the
|
||||
GStreamer website. Many of them were ported to Rust already and the code can
|
||||
be found in the
|
||||
[tutorials](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/master/tutorials)
|
||||
directory.
|
||||
|
||||
Some further examples for various aspects of GStreamer and how to use it from
|
||||
Rust can be found in the
|
||||
[examples](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/master/examples)
|
||||
directory.
|
||||
|
||||
Various GStreamer plugins written in Rust can be found in the
|
||||
[gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs)
|
||||
repository.
|
||||
|
||||
<a name="license"/>
|
||||
|
||||
## LICENSE
|
||||
|
||||
gstreamer-rs and all crates contained in here are licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
GStreamer itself is licensed under the Lesser General Public License version
|
||||
2.1 or (at your option) any later version:
|
||||
https://www.gnu.org/licenses/lgpl-2.1.html
|
||||
|
||||
<a name="contribution"/>
|
||||
|
||||
## Contribution
|
||||
|
||||
Any kinds of contributions are welcome as a pull request.
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in gstreamer-rs by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
|
@ -1,4 +1,5 @@
|
|||
use glib::translate::{from_glib, FromGlibPtrFull};
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
||||
|
@ -8,12 +9,25 @@ use gst_rtp_sys;
|
|||
pub enum Readable {}
|
||||
pub enum Writable {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RTPBuffer<'a, T>(gst_rtp_sys::GstRTPBuffer, &'a gst::Buffer, PhantomData<T>);
|
||||
pub struct RTPBuffer<'a, T> {
|
||||
rtp_buffer: gst_rtp_sys::GstRTPBuffer,
|
||||
buffer: &'a gst::Buffer,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
unsafe impl<'a, T> Send for RTPBuffer<'a, T> {}
|
||||
unsafe impl<'a, T> Sync for RTPBuffer<'a, T> {}
|
||||
|
||||
impl<'a, T> fmt::Debug for RTPBuffer<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("RTPBuffer")
|
||||
.field("rtp_buffer", &self.rtp_buffer)
|
||||
.field("buffer", &self.buffer)
|
||||
.field("phantom", &self.phantom)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RTPBuffer<'a, Readable> {
|
||||
pub fn from_buffer_readable(
|
||||
buffer: &gst::Buffer,
|
||||
|
@ -27,7 +41,11 @@ impl<'a> RTPBuffer<'a, Readable> {
|
|||
));
|
||||
|
||||
if res {
|
||||
Ok(RTPBuffer(rtp_buffer.assume_init(), buffer, PhantomData))
|
||||
Ok(RTPBuffer {
|
||||
rtp_buffer: rtp_buffer.assume_init(),
|
||||
buffer,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(glib_bool_error!("Failed to map RTP buffer readable"))
|
||||
}
|
||||
|
@ -48,7 +66,11 @@ impl<'a> RTPBuffer<'a, Writable> {
|
|||
));
|
||||
|
||||
if res {
|
||||
Ok(RTPBuffer(rtp_buffer.assume_init(), buffer, PhantomData))
|
||||
Ok(RTPBuffer {
|
||||
rtp_buffer: rtp_buffer.assume_init(),
|
||||
buffer,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(glib_bool_error!("Failed to map RTP buffer writable"))
|
||||
}
|
||||
|
@ -57,41 +79,41 @@ impl<'a> RTPBuffer<'a, Writable> {
|
|||
|
||||
pub fn set_seq(&mut self, seq: u16) {
|
||||
unsafe {
|
||||
gst_rtp_sys::gst_rtp_buffer_set_seq(&mut self.0, seq);
|
||||
gst_rtp_sys::gst_rtp_buffer_set_seq(&mut self.rtp_buffer, seq);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_payload_type(&mut self, pt: u8) {
|
||||
unsafe {
|
||||
gst_rtp_sys::gst_rtp_buffer_set_payload_type(&mut self.0, pt);
|
||||
gst_rtp_sys::gst_rtp_buffer_set_payload_type(&mut self.rtp_buffer, pt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_timestamp(&mut self, rtptime: u32) {
|
||||
unsafe {
|
||||
gst_rtp_sys::gst_rtp_buffer_set_timestamp(&mut self.0, rtptime);
|
||||
gst_rtp_sys::gst_rtp_buffer_set_timestamp(&mut self.rtp_buffer, rtptime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RTPBuffer<'a, T> {
|
||||
pub fn get_seq(&mut self) -> u16 {
|
||||
unsafe { gst_rtp_sys::gst_rtp_buffer_get_seq(&mut self.0) }
|
||||
unsafe { gst_rtp_sys::gst_rtp_buffer_get_seq(&mut self.rtp_buffer) }
|
||||
}
|
||||
|
||||
pub fn get_payload_type(&mut self) -> u8 {
|
||||
unsafe { gst_rtp_sys::gst_rtp_buffer_get_payload_type(&mut self.0) }
|
||||
unsafe { gst_rtp_sys::gst_rtp_buffer_get_payload_type(&mut self.rtp_buffer) }
|
||||
}
|
||||
|
||||
pub fn get_timestamp(&mut self) -> u32 {
|
||||
unsafe { gst_rtp_sys::gst_rtp_buffer_get_timestamp(&mut self.0) }
|
||||
unsafe { gst_rtp_sys::gst_rtp_buffer_get_timestamp(&mut self.rtp_buffer) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for RTPBuffer<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gst_rtp_sys::gst_rtp_buffer_unmap(&mut self.0);
|
||||
gst_rtp_sys::gst_rtp_buffer_unmap(&mut self.rtp_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-rtsp-server"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Mathieu Duponchelle <mathieu@centricular.com>", "Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer RTSP Server library"
|
||||
|
@ -16,18 +16,20 @@ build = "build.rs"
|
|||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
lazy_static = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gio-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-rtsp-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-rtsp-server-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-net-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gio = { git = "https://github.com/gtk-rs/gio" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-rtsp = { path = "../gstreamer-rtsp" }
|
||||
gstreamer-net = { path = "../gstreamer-net" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gio-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-sdp-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-rtsp-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-rtsp-server-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-net-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gio = { version = "0.8" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-sdp = { version = "0.15", path = "../gstreamer-sdp" }
|
||||
gstreamer-rtsp = { version = "0.15", path = "../gstreamer-rtsp" }
|
||||
gstreamer-net = { version = "0.15", path = "../gstreamer-net" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -24,6 +24,7 @@ use RTSPMediaStatus;
|
|||
use RTSPPublishClockMode;
|
||||
use RTSPStream;
|
||||
use RTSPSuspendMode;
|
||||
use RTSPThread;
|
||||
use RTSPTransportMode;
|
||||
|
||||
glib_wrapper! {
|
||||
|
@ -123,7 +124,7 @@ pub trait RTSPMediaExt: 'static {
|
|||
|
||||
fn n_streams(&self) -> u32;
|
||||
|
||||
//fn prepare(&self, thread: /*Ignored*/Option<&mut RTSPThread>) -> bool;
|
||||
fn prepare(&self, thread: Option<&RTSPThread>) -> Result<(), glib::error::BoolError>;
|
||||
|
||||
//fn seek(&self, range: /*Ignored*/&mut gst_rtsp::RTSPTimeRange) -> bool;
|
||||
|
||||
|
@ -182,8 +183,6 @@ pub trait RTSPMediaExt: 'static {
|
|||
|
||||
fn suspend(&self) -> Result<(), glib::error::BoolError>;
|
||||
|
||||
fn take_pipeline<P: IsA<gst::Pipeline>>(&self, pipeline: &P);
|
||||
|
||||
fn unprepare(&self) -> Result<(), glib::error::BoolError>;
|
||||
|
||||
fn unsuspend(&self) -> Result<(), glib::error::BoolError>;
|
||||
|
@ -542,9 +541,17 @@ impl<O: IsA<RTSPMedia>> RTSPMediaExt for O {
|
|||
unsafe { gst_rtsp_server_sys::gst_rtsp_media_n_streams(self.as_ref().to_glib_none().0) }
|
||||
}
|
||||
|
||||
//fn prepare(&self, thread: /*Ignored*/Option<&mut RTSPThread>) -> bool {
|
||||
// unsafe { TODO: call gst_rtsp_server_sys:gst_rtsp_media_prepare() }
|
||||
//}
|
||||
fn prepare(&self, thread: Option<&RTSPThread>) -> Result<(), glib::error::BoolError> {
|
||||
unsafe {
|
||||
glib_result_from_gboolean!(
|
||||
gst_rtsp_server_sys::gst_rtsp_media_prepare(
|
||||
self.as_ref().to_glib_none().0,
|
||||
thread.to_glib_full()
|
||||
),
|
||||
"Failed to prepare media"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//fn seek(&self, range: /*Ignored*/&mut gst_rtsp::RTSPTimeRange) -> bool {
|
||||
// unsafe { TODO: call gst_rtsp_server_sys:gst_rtsp_media_seek() }
|
||||
|
@ -755,15 +762,6 @@ impl<O: IsA<RTSPMedia>> RTSPMediaExt for O {
|
|||
}
|
||||
}
|
||||
|
||||
fn take_pipeline<P: IsA<gst::Pipeline>>(&self, pipeline: &P) {
|
||||
unsafe {
|
||||
gst_rtsp_server_sys::gst_rtsp_media_take_pipeline(
|
||||
self.as_ref().to_glib_none().0,
|
||||
pipeline.as_ref().to_glib_full(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn unprepare(&self) -> Result<(), glib::error::BoolError> {
|
||||
unsafe {
|
||||
glib_result_from_gboolean!(
|
||||
|
|
|
@ -11,6 +11,9 @@ use glib_sys;
|
|||
use gst_rtsp_server_sys;
|
||||
use std::boxed::Box as Box_;
|
||||
use std::mem::transmute;
|
||||
use RTSPContext;
|
||||
use RTSPThread;
|
||||
use RTSPThreadType;
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct RTSPThreadPool(Object<gst_rtsp_server_sys::GstRTSPThreadPool, gst_rtsp_server_sys::GstRTSPThreadPoolClass, RTSPThreadPoolClass>);
|
||||
|
@ -48,7 +51,7 @@ pub const NONE_RTSP_THREAD_POOL: Option<&RTSPThreadPool> = None;
|
|||
pub trait RTSPThreadPoolExt: 'static {
|
||||
fn get_max_threads(&self) -> i32;
|
||||
|
||||
//fn get_thread(&self, type_: RTSPThreadType, ctx: &RTSPContext) -> /*Ignored*/Option<RTSPThread>;
|
||||
fn get_thread(&self, type_: RTSPThreadType, ctx: &RTSPContext) -> Option<RTSPThread>;
|
||||
|
||||
fn set_max_threads(&self, max_threads: i32);
|
||||
|
||||
|
@ -67,9 +70,15 @@ impl<O: IsA<RTSPThreadPool>> RTSPThreadPoolExt for O {
|
|||
}
|
||||
}
|
||||
|
||||
//fn get_thread(&self, type_: RTSPThreadType, ctx: &RTSPContext) -> /*Ignored*/Option<RTSPThread> {
|
||||
// unsafe { TODO: call gst_rtsp_server_sys:gst_rtsp_thread_pool_get_thread() }
|
||||
//}
|
||||
fn get_thread(&self, type_: RTSPThreadType, ctx: &RTSPContext) -> Option<RTSPThread> {
|
||||
unsafe {
|
||||
from_glib_full(gst_rtsp_server_sys::gst_rtsp_thread_pool_get_thread(
|
||||
self.as_ref().to_glib_none().0,
|
||||
type_.to_glib(),
|
||||
ctx.to_glib_none().0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn set_max_threads(&self, max_threads: i32) {
|
||||
unsafe {
|
||||
|
|
|
@ -26,6 +26,8 @@ extern crate gstreamer_net_sys as gst_net_sys;
|
|||
extern crate gstreamer_rtsp as gst_rtsp;
|
||||
extern crate gstreamer_rtsp_server_sys as gst_rtsp_server_sys;
|
||||
extern crate gstreamer_rtsp_sys as gst_rtsp_sys;
|
||||
extern crate gstreamer_sdp as gst_sdp;
|
||||
extern crate gstreamer_sdp_sys as gst_sdp_sys;
|
||||
extern crate gstreamer_sys as gst_sys;
|
||||
|
||||
macro_rules! assert_initialized_main_thread {
|
||||
|
@ -52,21 +54,27 @@ mod rtsp_address_pool;
|
|||
mod rtsp_auth;
|
||||
mod rtsp_client;
|
||||
mod rtsp_context;
|
||||
mod rtsp_media;
|
||||
mod rtsp_media_factory;
|
||||
mod rtsp_server;
|
||||
mod rtsp_session_pool;
|
||||
mod rtsp_stream;
|
||||
mod rtsp_stream_transport;
|
||||
mod rtsp_thread;
|
||||
mod rtsp_token;
|
||||
|
||||
pub mod subclass;
|
||||
|
||||
pub use rtsp_address_pool::RTSPAddressPoolExtManual;
|
||||
pub use rtsp_auth::RTSPAuthExtManual;
|
||||
pub use rtsp_client::RTSPClientExtManual;
|
||||
pub use rtsp_media::RTSPMediaExtManual;
|
||||
pub use rtsp_media_factory::RTSPMediaFactoryExtManual;
|
||||
pub use rtsp_server::RTSPServerExtManual;
|
||||
pub use rtsp_session_pool::RTSPSessionPoolExtManual;
|
||||
pub use rtsp_stream::RTSPStreamExtManual;
|
||||
pub use rtsp_stream_transport::RTSPStreamTransportExtManual;
|
||||
pub use rtsp_thread::*;
|
||||
|
||||
pub use rtsp_context::*;
|
||||
pub use rtsp_token::*;
|
||||
|
@ -140,6 +148,7 @@ pub mod prelude {
|
|||
pub use rtsp_address_pool::RTSPAddressPoolExtManual;
|
||||
pub use rtsp_auth::RTSPAuthExtManual;
|
||||
pub use rtsp_client::RTSPClientExtManual;
|
||||
pub use rtsp_media::RTSPMediaExtManual;
|
||||
pub use rtsp_media_factory::RTSPMediaFactoryExtManual;
|
||||
pub use rtsp_server::RTSPServerExtManual;
|
||||
pub use rtsp_session_pool::RTSPSessionPoolExtManual;
|
||||
|
|
|
@ -37,3 +37,18 @@ impl glib::translate::FromGlibPtrBorrow<*mut gst_rtsp_server_sys::GstRTSPContext
|
|||
RTSPContext(ptr::NonNull::new_unchecked(ptr))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<'a> glib::translate::ToGlibPtr<'a, *mut gst_rtsp_server_sys::GstRTSPContext> for RTSPContext {
|
||||
type Storage = &'a RTSPContext;
|
||||
|
||||
fn to_glib_none(
|
||||
&'a self,
|
||||
) -> glib::translate::Stash<'a, *mut gst_rtsp_server_sys::GstRTSPContext, Self> {
|
||||
glib::translate::Stash(self.0.as_ptr(), self)
|
||||
}
|
||||
|
||||
fn to_glib_full(&self) -> *mut gst_rtsp_server_sys::GstRTSPContext {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
27
gstreamer-rtsp-server/src/rtsp_media.rs
Normal file
27
gstreamer-rtsp-server/src/rtsp_media.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use glib::object::IsA;
|
||||
use glib::translate::*;
|
||||
use gst;
|
||||
use gst_rtsp_server_sys;
|
||||
|
||||
use RTSPMedia;
|
||||
|
||||
pub trait RTSPMediaExtManual: 'static {
|
||||
fn take_pipeline<P: IsA<gst::Pipeline>>(&self, pipeline: &P);
|
||||
}
|
||||
|
||||
impl<O: IsA<RTSPMedia>> RTSPMediaExtManual for O {
|
||||
fn take_pipeline<P: IsA<gst::Pipeline>>(&self, pipeline: &P) {
|
||||
unsafe {
|
||||
let pipeline = pipeline.as_ref().to_glib_full();
|
||||
// See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/109
|
||||
gobject_sys::g_object_force_floating(pipeline as *mut _);
|
||||
gst_rtsp_server_sys::gst_rtsp_media_take_pipeline(
|
||||
self.as_ref().to_glib_none().0,
|
||||
pipeline,
|
||||
);
|
||||
if gobject_sys::g_object_is_floating(pipeline as *mut _) != glib_sys::GFALSE {
|
||||
gobject_sys::g_object_ref_sink(pipeline as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
gstreamer-rtsp-server/src/rtsp_thread.rs
Normal file
47
gstreamer-rtsp-server/src/rtsp_thread.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use glib;
|
||||
use glib::translate::*;
|
||||
use gst_rtsp_server_sys;
|
||||
|
||||
use gst::prelude::*;
|
||||
|
||||
gst_define_mini_object_wrapper!(
|
||||
RTSPThread,
|
||||
RTSPThreadRef,
|
||||
gst_rtsp_server_sys::GstRTSPThread,
|
||||
[],
|
||||
|| gst_rtsp_server_sys::gst_rtsp_thread_get_type()
|
||||
);
|
||||
|
||||
impl RTSPThread {
|
||||
pub fn new(type_: ::RTSPThreadType) -> Option<Self> {
|
||||
unsafe { from_glib_full(gst_rtsp_server_sys::gst_rtsp_thread_new(type_.to_glib())) }
|
||||
}
|
||||
}
|
||||
|
||||
impl RTSPThreadRef {
|
||||
pub fn reuse(&self) -> bool {
|
||||
unsafe {
|
||||
from_glib(gst_rtsp_server_sys::gst_rtsp_thread_reuse(
|
||||
self.as_mut_ptr(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&self) {
|
||||
unsafe {
|
||||
gst_rtsp_server_sys::gst_rtsp_thread_stop(self.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_(&self) -> ::RTSPThreadType {
|
||||
unsafe { from_glib((*self.as_ptr()).type_) }
|
||||
}
|
||||
|
||||
pub fn context(&self) -> glib::MainContext {
|
||||
unsafe { from_glib_none((*self.as_ptr()).context) }
|
||||
}
|
||||
|
||||
pub fn loop_(&self) -> glib::MainLoop {
|
||||
unsafe { from_glib_none((*self.as_ptr()).loop_) }
|
||||
}
|
||||
}
|
20
gstreamer-rtsp-server/src/subclass/mod.rs
Normal file
20
gstreamer-rtsp-server/src/subclass/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![allow(clippy::cast_ptr_alignment)]
|
||||
|
||||
pub mod rtsp_client;
|
||||
pub mod rtsp_media;
|
||||
pub mod rtsp_media_factory;
|
||||
pub mod rtsp_server;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::rtsp_client::{RTSPClientImpl, RTSPClientImplExt};
|
||||
pub use super::rtsp_media::{RTSPMediaImpl, RTSPMediaImplExt};
|
||||
pub use super::rtsp_media_factory::{RTSPMediaFactoryImpl, RTSPMediaFactoryImplExt};
|
||||
pub use super::rtsp_server::{RTSPServerImpl, RTSPServerImplExt};
|
||||
}
|
1283
gstreamer-rtsp-server/src/subclass/rtsp_client.rs
Normal file
1283
gstreamer-rtsp-server/src/subclass/rtsp_client.rs
Normal file
File diff suppressed because it is too large
Load diff
780
gstreamer-rtsp-server/src/subclass/rtsp_media.rs
Normal file
780
gstreamer-rtsp-server/src/subclass/rtsp_media.rs
Normal file
|
@ -0,0 +1,780 @@
|
|||
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use gst_rtsp_server_sys;
|
||||
|
||||
use glib::translate::*;
|
||||
|
||||
use glib::subclass::prelude::*;
|
||||
|
||||
use gst::prelude::*;
|
||||
use std::ptr;
|
||||
|
||||
use RTSPMedia;
|
||||
use RTSPMediaClass;
|
||||
use RTSPThread;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SDPInfo(ptr::NonNull<gst_rtsp_server_sys::GstSDPInfo>);
|
||||
|
||||
impl SDPInfo {
|
||||
pub fn is_ipv6(&self) -> bool {
|
||||
unsafe { from_glib(self.0.as_ref().is_ipv6) }
|
||||
}
|
||||
|
||||
pub fn server_ip(&self) -> &str {
|
||||
unsafe {
|
||||
use std::ffi::CStr;
|
||||
CStr::from_ptr(self.0.as_ref().server_ip).to_str().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RTSPMediaImpl: RTSPMediaImplExt + ObjectImpl + Send + Sync + 'static {
|
||||
fn handle_message(&self, media: &RTSPMedia, message: &gst::MessageRef) -> bool {
|
||||
self.parent_handle_message(media, message)
|
||||
}
|
||||
|
||||
fn prepare(&self, media: &RTSPMedia, thread: &RTSPThread) -> Result<(), gst::LoggableError> {
|
||||
self.parent_prepare(media, thread)
|
||||
}
|
||||
|
||||
fn unprepare(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError> {
|
||||
self.parent_unprepare(media)
|
||||
}
|
||||
|
||||
fn suspend(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError> {
|
||||
self.parent_suspend(media)
|
||||
}
|
||||
|
||||
fn unsuspend(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError> {
|
||||
self.parent_unsuspend(media)
|
||||
}
|
||||
|
||||
// TODO missing: convert_range
|
||||
|
||||
fn query_position(&self, media: &RTSPMedia) -> Option<gst::ClockTime> {
|
||||
self.parent_query_position(media)
|
||||
}
|
||||
|
||||
fn query_stop(&self, media: &RTSPMedia) -> Option<gst::ClockTime> {
|
||||
self.parent_query_stop(media)
|
||||
}
|
||||
|
||||
fn create_rtpbin(&self, media: &RTSPMedia) -> Option<gst::Element> {
|
||||
self.parent_create_rtpbin(media)
|
||||
}
|
||||
|
||||
fn setup_rtpbin(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
rtpbin: &gst::Element,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.parent_setup_rtpbin(media, rtpbin)
|
||||
}
|
||||
|
||||
fn setup_sdp(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
sdp: &mut gst_sdp::SDPMessageRef,
|
||||
info: &SDPInfo,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.parent_setup_sdp(media, sdp, info)
|
||||
}
|
||||
|
||||
fn new_stream(&self, media: &RTSPMedia, stream: &::RTSPStream) {
|
||||
self.parent_new_stream(media, stream);
|
||||
}
|
||||
|
||||
fn removed_stream(&self, media: &RTSPMedia, stream: &::RTSPStream) {
|
||||
self.parent_removed_stream(media, stream);
|
||||
}
|
||||
|
||||
fn prepared(&self, media: &RTSPMedia) {
|
||||
self.parent_prepared(media);
|
||||
}
|
||||
|
||||
fn unprepared(&self, media: &RTSPMedia) {
|
||||
self.parent_unprepared(media);
|
||||
}
|
||||
|
||||
fn target_state(&self, media: &RTSPMedia, state: gst::State) {
|
||||
self.parent_target_state(media, state);
|
||||
}
|
||||
|
||||
fn new_state(&self, media: &RTSPMedia, state: gst::State) {
|
||||
self.parent_new_state(media, state);
|
||||
}
|
||||
|
||||
fn handle_sdp(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
sdp: &gst_sdp::SDPMessageRef,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.parent_handle_sdp(media, sdp)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RTSPMediaImplExt {
|
||||
fn parent_handle_message(&self, media: &RTSPMedia, message: &gst::MessageRef) -> bool;
|
||||
fn parent_prepare(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
thread: &RTSPThread,
|
||||
) -> Result<(), gst::LoggableError>;
|
||||
fn parent_unprepare(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError>;
|
||||
fn parent_suspend(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError>;
|
||||
fn parent_unsuspend(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError>;
|
||||
// TODO missing: convert_range
|
||||
|
||||
fn parent_query_position(&self, media: &RTSPMedia) -> Option<gst::ClockTime>;
|
||||
fn parent_query_stop(&self, media: &RTSPMedia) -> Option<gst::ClockTime>;
|
||||
fn parent_create_rtpbin(&self, media: &RTSPMedia) -> Option<gst::Element>;
|
||||
fn parent_setup_rtpbin(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
rtpbin: &gst::Element,
|
||||
) -> Result<(), gst::LoggableError>;
|
||||
fn parent_setup_sdp(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
sdp: &mut gst_sdp::SDPMessageRef,
|
||||
info: &SDPInfo,
|
||||
) -> Result<(), gst::LoggableError>;
|
||||
fn parent_new_stream(&self, media: &RTSPMedia, stream: &::RTSPStream);
|
||||
fn parent_removed_stream(&self, media: &RTSPMedia, stream: &::RTSPStream);
|
||||
fn parent_prepared(&self, media: &RTSPMedia);
|
||||
fn parent_unprepared(&self, media: &RTSPMedia);
|
||||
fn parent_target_state(&self, media: &RTSPMedia, state: gst::State);
|
||||
fn parent_new_state(&self, media: &RTSPMedia, state: gst::State);
|
||||
fn parent_handle_sdp(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
sdp: &gst_sdp::SDPMessageRef,
|
||||
) -> Result<(), gst::LoggableError>;
|
||||
}
|
||||
|
||||
impl<T: RTSPMediaImpl + ObjectImpl> RTSPMediaImplExt for T {
|
||||
fn parent_handle_message(&self, media: &RTSPMedia, message: &gst::MessageRef) -> bool {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).handle_message {
|
||||
from_glib(f(media.to_glib_none().0, message.as_ptr() as *mut _))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_prepare(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
thread: &RTSPThread,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).prepare {
|
||||
gst_result_from_gboolean!(
|
||||
f(media.to_glib_none().0, thread.to_glib_none().0),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `prepare` failed"
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_unprepare(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).unprepare {
|
||||
gst_result_from_gboolean!(
|
||||
f(media.to_glib_none().0),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `unprepare` failed"
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_suspend(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).suspend {
|
||||
gst_result_from_gboolean!(
|
||||
f(media.to_glib_none().0),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `suspend` failed"
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_unsuspend(&self, media: &RTSPMedia) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).unsuspend {
|
||||
gst_result_from_gboolean!(
|
||||
f(media.to_glib_none().0),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `unsuspend` failed"
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO missing: convert_range
|
||||
|
||||
fn parent_query_position(&self, media: &RTSPMedia) -> Option<gst::ClockTime> {
|
||||
unsafe {
|
||||
use std::mem;
|
||||
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).query_position {
|
||||
let mut position = mem::MaybeUninit::uninit();
|
||||
if f(media.to_glib_none().0, position.as_mut_ptr()) == glib_sys::GFALSE {
|
||||
None
|
||||
} else {
|
||||
Some(from_glib(position.assume_init() as u64))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_query_stop(&self, media: &RTSPMedia) -> Option<gst::ClockTime> {
|
||||
unsafe {
|
||||
use std::mem;
|
||||
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).query_stop {
|
||||
let mut stop = mem::MaybeUninit::uninit();
|
||||
if f(media.to_glib_none().0, stop.as_mut_ptr()) == glib_sys::GFALSE {
|
||||
None
|
||||
} else {
|
||||
Some(from_glib(stop.assume_init() as u64))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_create_rtpbin(&self, media: &RTSPMedia) -> Option<gst::Element> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
let f = (*parent_class)
|
||||
.create_rtpbin
|
||||
.expect("No `create_rtpbin` virtual method implementation in parent class");
|
||||
|
||||
from_glib_none(f(media.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_setup_rtpbin(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
rtpbin: &gst::Element,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).setup_rtpbin {
|
||||
let ptr = rtpbin.to_glib_none().0;
|
||||
|
||||
// The C code assumes to pass a floating reference around so let's make sure we do
|
||||
gobject_sys::g_object_force_floating(ptr as *mut _);
|
||||
|
||||
let res = gst_result_from_gboolean!(
|
||||
f(media.to_glib_none().0, ptr),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `setup_sdp` failed"
|
||||
);
|
||||
|
||||
// If the code didn't accidentally sink it then we have to do that
|
||||
// here now so that we don't have any floating reference on our side
|
||||
// anymore
|
||||
if gobject_sys::g_object_is_floating(ptr as *mut _) != glib_sys::GFALSE {
|
||||
gobject_sys::g_object_ref_sink(ptr as *mut _);
|
||||
}
|
||||
|
||||
res
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_setup_sdp(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
sdp: &mut gst_sdp::SDPMessageRef,
|
||||
info: &SDPInfo,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
let f = (*parent_class)
|
||||
.setup_sdp
|
||||
.expect("No `setup_sdp` virtual method implementation in parent class");
|
||||
|
||||
gst_result_from_gboolean!(
|
||||
f(
|
||||
media.to_glib_none().0,
|
||||
sdp as *mut _ as *mut gst_sdp_sys::GstSDPMessage,
|
||||
info.0.as_ptr()
|
||||
),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `setup_sdp` failed"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_new_stream(&self, media: &RTSPMedia, stream: &::RTSPStream) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).new_stream {
|
||||
f(media.to_glib_none().0, stream.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_removed_stream(&self, media: &RTSPMedia, stream: &::RTSPStream) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).removed_stream {
|
||||
f(media.to_glib_none().0, stream.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_prepared(&self, media: &RTSPMedia) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).prepared {
|
||||
f(media.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_unprepared(&self, media: &RTSPMedia) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).unprepared {
|
||||
f(media.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_target_state(&self, media: &RTSPMedia, state: gst::State) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).target_state {
|
||||
f(media.to_glib_none().0, state.to_glib());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_new_state(&self, media: &RTSPMedia, state: gst::State) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
if let Some(f) = (*parent_class).new_state {
|
||||
f(media.to_glib_none().0, state.to_glib());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_handle_sdp(
|
||||
&self,
|
||||
media: &RTSPMedia,
|
||||
sdp: &gst_sdp::SDPMessageRef,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPMediaClass;
|
||||
let f = (*parent_class)
|
||||
.handle_sdp
|
||||
.expect("No `handle_sdp` virtual method implementation in parent class");
|
||||
|
||||
gst_result_from_gboolean!(
|
||||
f(
|
||||
media.to_glib_none().0,
|
||||
sdp as *const _ as *mut gst_sdp_sys::GstSDPMessage
|
||||
),
|
||||
gst::CAT_RUST,
|
||||
"Parent function `handle_sdp` failed"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe impl<T: ObjectSubclass + RTSPMediaImpl> IsSubclassable<T> for RTSPMediaClass {
|
||||
fn override_vfuncs(&mut self) {
|
||||
<glib::ObjectClass as IsSubclassable<T>>::override_vfuncs(self);
|
||||
unsafe {
|
||||
let klass = &mut *(self as *mut Self as *mut gst_rtsp_server_sys::GstRTSPMediaClass);
|
||||
klass.handle_message = Some(media_handle_message::<T>);
|
||||
klass.prepare = Some(media_prepare::<T>);
|
||||
klass.unprepare = Some(media_unprepare::<T>);
|
||||
klass.suspend = Some(media_suspend::<T>);
|
||||
klass.unsuspend = Some(media_unsuspend::<T>);
|
||||
klass.query_position = Some(media_query_position::<T>);
|
||||
klass.query_stop = Some(media_query_stop::<T>);
|
||||
klass.create_rtpbin = Some(media_create_rtpbin::<T>);
|
||||
klass.setup_rtpbin = Some(media_setup_rtpbin::<T>);
|
||||
klass.setup_sdp = Some(media_setup_sdp::<T>);
|
||||
klass.new_stream = Some(media_new_stream::<T>);
|
||||
klass.removed_stream = Some(media_removed_stream::<T>);
|
||||
klass.prepared = Some(media_prepared::<T>);
|
||||
klass.unprepared = Some(media_unprepared::<T>);
|
||||
klass.target_state = Some(media_target_state::<T>);
|
||||
klass.new_state = Some(media_new_state::<T>);
|
||||
klass.handle_sdp = Some(media_handle_sdp::<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_handle_message<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
message: *mut gst_sys::GstMessage,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.handle_message(&wrap, gst::MessageRef::from_ptr(message))
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_prepare<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
thread: *mut gst_rtsp_server_sys::GstRTSPThread,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.prepare(&wrap, &from_glib_borrow(thread)) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_unprepare<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.unprepare(&wrap) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_suspend<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.suspend(&wrap) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_unsuspend<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.unsuspend(&wrap) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_query_position<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
position: *mut i64,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.query_position(&wrap) {
|
||||
Some(pos) => {
|
||||
*position = pos.to_glib() as i64;
|
||||
glib_sys::GTRUE
|
||||
}
|
||||
None => glib_sys::GFALSE,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_query_stop<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
stop: *mut i64,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.query_stop(&wrap) {
|
||||
Some(s) => {
|
||||
*stop = s.to_glib() as i64;
|
||||
glib_sys::GTRUE
|
||||
}
|
||||
None => glib_sys::GFALSE,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_create_rtpbin<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) -> *mut gst_sys::GstElement
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
let res: *mut gst_sys::GstElement = imp.create_rtpbin(&wrap).to_glib_full();
|
||||
|
||||
if !res.is_null() {
|
||||
gobject_sys::g_object_force_floating(res as *mut _);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_setup_rtpbin<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
rtpbin: *mut gst_sys::GstElement,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
// If the rtpbin was floating before make sure it is not anymore for now so
|
||||
// we don't accidentally take ownership of it somewhere along the line
|
||||
if gobject_sys::g_object_is_floating(rtpbin as *mut _) != glib_sys::GFALSE {
|
||||
gobject_sys::g_object_ref_sink(rtpbin as *mut _);
|
||||
}
|
||||
|
||||
let res = match imp.setup_rtpbin(&wrap, &from_glib_borrow(rtpbin)) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure that the rtpbin is still floating afterwards here
|
||||
gobject_sys::g_object_force_floating(rtpbin as *mut _);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_setup_sdp<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
sdp: *mut gst_sdp_sys::GstSDPMessage,
|
||||
info: *mut gst_rtsp_server_sys::GstSDPInfo,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.setup_sdp(
|
||||
&wrap,
|
||||
&mut *(sdp as *mut gst_sdp::SDPMessageRef),
|
||||
&SDPInfo(ptr::NonNull::new(info).expect("NULL SDPInfo")),
|
||||
) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_new_stream<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
stream: *mut gst_rtsp_server_sys::GstRTSPStream,
|
||||
) where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.new_stream(&wrap, &from_glib_borrow(stream));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_removed_stream<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
stream: *mut gst_rtsp_server_sys::GstRTSPStream,
|
||||
) where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.removed_stream(&wrap, &from_glib_borrow(stream));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_prepared<T: ObjectSubclass>(ptr: *mut gst_rtsp_server_sys::GstRTSPMedia)
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.prepared(&wrap);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_unprepared<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.unprepared(&wrap);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_target_state<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
state: gst_sys::GstState,
|
||||
) where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.target_state(&wrap, from_glib(state));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_new_state<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
state: gst_sys::GstState,
|
||||
) where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
imp.new_state(&wrap, from_glib(state));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn media_handle_sdp<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
sdp: *mut gst_sdp_sys::GstSDPMessage,
|
||||
) -> glib_sys::gboolean
|
||||
where
|
||||
T: RTSPMediaImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMedia = from_glib_borrow(ptr);
|
||||
|
||||
match imp.handle_sdp(&wrap, &*(sdp as *const gst_sdp::SDPMessageRef)) {
|
||||
Ok(()) => glib_sys::GTRUE,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
glib_sys::GFALSE
|
||||
}
|
||||
}
|
||||
}
|
338
gstreamer-rtsp-server/src/subclass/rtsp_media_factory.rs
Normal file
338
gstreamer-rtsp-server/src/subclass/rtsp_media_factory.rs
Normal file
|
@ -0,0 +1,338 @@
|
|||
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use gst_rtsp_server_sys;
|
||||
|
||||
use glib::translate::*;
|
||||
use gst_rtsp;
|
||||
|
||||
use glib::subclass::prelude::*;
|
||||
|
||||
use RTSPMediaFactory;
|
||||
use RTSPMediaFactoryClass;
|
||||
|
||||
pub trait RTSPMediaFactoryImpl:
|
||||
RTSPMediaFactoryImplExt + ObjectImpl + Send + Sync + 'static
|
||||
{
|
||||
fn gen_key(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<glib::GString> {
|
||||
self.parent_gen_key(factory, url)
|
||||
}
|
||||
|
||||
fn create_element(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<gst::Element> {
|
||||
self.parent_create_element(factory, url)
|
||||
}
|
||||
|
||||
fn construct(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<::RTSPMedia> {
|
||||
self.parent_construct(factory, url)
|
||||
}
|
||||
|
||||
fn create_pipeline(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
media: &::RTSPMedia,
|
||||
) -> Option<gst::Pipeline> {
|
||||
self.parent_create_pipeline(factory, media)
|
||||
}
|
||||
|
||||
fn configure(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia) {
|
||||
self.parent_configure(factory, media)
|
||||
}
|
||||
|
||||
fn media_constructed(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia) {
|
||||
self.parent_media_constructed(factory, media)
|
||||
}
|
||||
|
||||
fn media_configure(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia) {
|
||||
self.parent_media_configure(factory, media)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RTSPMediaFactoryImplExt {
|
||||
fn parent_gen_key(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<glib::GString>;
|
||||
|
||||
fn parent_create_element(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<gst::Element>;
|
||||
|
||||
fn parent_construct(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<::RTSPMedia>;
|
||||
|
||||
fn parent_create_pipeline(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
media: &::RTSPMedia,
|
||||
) -> Option<gst::Pipeline>;
|
||||
|
||||
fn parent_configure(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia);
|
||||
|
||||
fn parent_media_constructed(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia);
|
||||
fn parent_media_configure(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia);
|
||||
}
|
||||
|
||||
impl<T: RTSPMediaFactoryImpl + ObjectImpl> RTSPMediaFactoryImplExt for T {
|
||||
fn parent_gen_key(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<glib::GString> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
(*parent_class)
|
||||
.gen_key
|
||||
.map(|f| from_glib_full(f(factory.to_glib_none().0, url.to_glib_none().0)))
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_create_element(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<gst::Element> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
(*parent_class)
|
||||
.create_element
|
||||
.map(|f| from_glib_none(f(factory.to_glib_none().0, url.to_glib_none().0)))
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_construct(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
url: &gst_rtsp::RTSPUrl,
|
||||
) -> Option<::RTSPMedia> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
(*parent_class)
|
||||
.construct
|
||||
.map(|f| from_glib_full(f(factory.to_glib_none().0, url.to_glib_none().0)))
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_create_pipeline(
|
||||
&self,
|
||||
factory: &RTSPMediaFactory,
|
||||
media: &::RTSPMedia,
|
||||
) -> Option<gst::Pipeline> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
(*parent_class)
|
||||
.create_pipeline
|
||||
.map(|f| {
|
||||
let ptr = f(factory.to_glib_none().0, media.to_glib_none().0)
|
||||
as *mut gst_sys::GstPipeline;
|
||||
|
||||
// See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/109
|
||||
if gobject_sys::g_object_is_floating(ptr as *mut _) != glib_sys::GFALSE {
|
||||
gobject_sys::g_object_ref_sink(ptr as *mut _);
|
||||
}
|
||||
from_glib_none(ptr)
|
||||
})
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_configure(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
if let Some(f) = (*parent_class).configure {
|
||||
f(factory.to_glib_none().0, media.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_media_constructed(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
if let Some(f) = (*parent_class).media_constructed {
|
||||
f(factory.to_glib_none().0, media.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_media_configure(&self, factory: &RTSPMediaFactory, media: &::RTSPMedia) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class = data.as_ref().get_parent_class()
|
||||
as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass;
|
||||
if let Some(f) = (*parent_class).media_configure {
|
||||
f(factory.to_glib_none().0, media.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe impl<T: ObjectSubclass + RTSPMediaFactoryImpl> IsSubclassable<T> for RTSPMediaFactoryClass {
|
||||
fn override_vfuncs(&mut self) {
|
||||
<glib::ObjectClass as IsSubclassable<T>>::override_vfuncs(self);
|
||||
unsafe {
|
||||
let klass =
|
||||
&mut *(self as *mut Self as *mut gst_rtsp_server_sys::GstRTSPMediaFactoryClass);
|
||||
klass.gen_key = Some(factory_gen_key::<T>);
|
||||
klass.create_element = Some(factory_create_element::<T>);
|
||||
klass.construct = Some(factory_construct::<T>);
|
||||
klass.create_pipeline = Some(factory_create_pipeline::<T>);
|
||||
klass.configure = Some(factory_configure::<T>);
|
||||
klass.media_constructed = Some(factory_media_constructed::<T>);
|
||||
klass.media_configure = Some(factory_media_configure::<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_gen_key<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
url: *const gst_rtsp_sys::GstRTSPUrl,
|
||||
) -> *mut std::os::raw::c_char
|
||||
where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
imp.gen_key(&wrap, &from_glib_borrow(url)).to_glib_full()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_create_element<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
url: *const gst_rtsp_sys::GstRTSPUrl,
|
||||
) -> *mut gst_sys::GstElement
|
||||
where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
let element = imp
|
||||
.create_element(&wrap, &from_glib_borrow(url))
|
||||
.to_glib_full();
|
||||
gobject_sys::g_object_force_floating(element as *mut _);
|
||||
element
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_construct<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
url: *const gst_rtsp_sys::GstRTSPUrl,
|
||||
) -> *mut gst_rtsp_server_sys::GstRTSPMedia
|
||||
where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
imp.construct(&wrap, &from_glib_borrow(url)).to_glib_full()
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref PIPELINE_QUARK: glib::Quark =
|
||||
glib::Quark::from_string("gstreamer-rs-rtsp-media-pipeline");
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_create_pipeline<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
media: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) -> *mut gst_sys::GstElement
|
||||
where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
use std::mem;
|
||||
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
let pipeline: *mut gst_sys::GstPipeline = imp
|
||||
.create_pipeline(&wrap, &from_glib_borrow(media))
|
||||
.to_glib_full();
|
||||
|
||||
// FIXME We somehow need to ensure the pipeline actually stays alive...
|
||||
gobject_sys::g_object_set_qdata_full(
|
||||
media as *mut _,
|
||||
PIPELINE_QUARK.to_glib(),
|
||||
pipeline as *mut _,
|
||||
Some(mem::transmute(gobject_sys::g_object_unref as usize)),
|
||||
);
|
||||
|
||||
pipeline as *mut _
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_configure<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
media: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
imp.configure(&wrap, &from_glib_borrow(media));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_media_constructed<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
media: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
imp.media_constructed(&wrap, &from_glib_borrow(media));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn factory_media_configure<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPMediaFactory,
|
||||
media: *mut gst_rtsp_server_sys::GstRTSPMedia,
|
||||
) where
|
||||
T: RTSPMediaFactoryImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPMediaFactory = from_glib_borrow(ptr);
|
||||
|
||||
imp.media_configure(&wrap, &from_glib_borrow(media));
|
||||
}
|
92
gstreamer-rtsp-server/src/subclass/rtsp_server.rs
Normal file
92
gstreamer-rtsp-server/src/subclass/rtsp_server.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use gst_rtsp_server_sys;
|
||||
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
|
||||
use RTSPServer;
|
||||
use RTSPServerClass;
|
||||
|
||||
pub trait RTSPServerImpl: RTSPServerImplExt + ObjectImpl + Send + Sync + 'static {
|
||||
fn create_client(&self, server: &RTSPServer) -> Option<::RTSPClient> {
|
||||
self.parent_create_client(server)
|
||||
}
|
||||
|
||||
fn client_connected(&self, server: &RTSPServer, client: &::RTSPClient) {
|
||||
self.parent_client_connected(server, client);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RTSPServerImplExt {
|
||||
fn parent_create_client(&self, server: &RTSPServer) -> Option<::RTSPClient>;
|
||||
|
||||
fn parent_client_connected(&self, server: &RTSPServer, client: &::RTSPClient);
|
||||
}
|
||||
|
||||
impl<T: RTSPServerImpl + ObjectImpl> RTSPServerImplExt for T {
|
||||
fn parent_create_client(&self, server: &RTSPServer) -> Option<::RTSPClient> {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPServerClass;
|
||||
let f = (*parent_class)
|
||||
.create_client
|
||||
.expect("No `create_client` virtual method implementation in parent class");
|
||||
from_glib_full(f(server.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_client_connected(&self, server: &RTSPServer, client: &::RTSPClient) {
|
||||
unsafe {
|
||||
let data = self.get_type_data();
|
||||
let parent_class =
|
||||
data.as_ref().get_parent_class() as *mut gst_rtsp_server_sys::GstRTSPServerClass;
|
||||
if let Some(f) = (*parent_class).client_connected {
|
||||
f(server.to_glib_none().0, client.to_glib_none().0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe impl<T: ObjectSubclass + RTSPServerImpl> IsSubclassable<T> for RTSPServerClass {
|
||||
fn override_vfuncs(&mut self) {
|
||||
<glib::ObjectClass as IsSubclassable<T>>::override_vfuncs(self);
|
||||
unsafe {
|
||||
let klass = &mut *(self as *mut Self as *mut gst_rtsp_server_sys::GstRTSPServerClass);
|
||||
klass.create_client = Some(server_create_client::<T>);
|
||||
klass.client_connected = Some(server_client_connected::<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn server_create_client<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPServer,
|
||||
) -> *mut gst_rtsp_server_sys::GstRTSPClient
|
||||
where
|
||||
T: RTSPServerImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPServer = from_glib_borrow(ptr);
|
||||
|
||||
imp.create_client(&wrap).to_glib_full()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn server_client_connected<T: ObjectSubclass>(
|
||||
ptr: *mut gst_rtsp_server_sys::GstRTSPServer,
|
||||
client: *mut gst_rtsp_server_sys::GstRTSPClient,
|
||||
) where
|
||||
T: RTSPServerImpl,
|
||||
{
|
||||
let instance = &*(ptr as *mut T::Instance);
|
||||
let imp = instance.get_impl();
|
||||
let wrap: RTSPServer = from_glib_borrow(ptr);
|
||||
|
||||
imp.client_connected(&wrap, &from_glib_borrow(client));
|
||||
}
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-rtsp"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Mathieu Duponchelle <mathieu@centricular.com>", "Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Rtsp library"
|
||||
|
@ -15,16 +15,16 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gio-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-rtsp-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-sdp-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gio = { git = "https://github.com/gtk-rs/gio" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-sdp = { path = "../gstreamer-sdp" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gio-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-rtsp-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-sdp-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gio = { version = "0.8" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-sdp = { version = "0.15", path = "../gstreamer-sdp" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-sdp"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Mathieu Duponchelle <mathieu@centricular.com>", "Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Sdp library"
|
||||
|
@ -13,12 +13,12 @@ keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-sdp-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-sdp-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-video"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Video library"
|
||||
|
@ -15,15 +15,17 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-video-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-base = { path = "../gstreamer-base" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-video-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer" }
|
||||
gstreamer-base = { version = "0.15", path = "../gstreamer-base" }
|
||||
lazy_static = "1.0"
|
||||
futures-channel = "0.3"
|
||||
futures-util = "0.3"
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -12,6 +12,66 @@ use glib::Type;
|
|||
use gobject_sys;
|
||||
use gst_video_sys;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoAlphaMode {
|
||||
Copy,
|
||||
Set,
|
||||
Mult,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoAlphaMode {
|
||||
type GlibType = gst_video_sys::GstVideoAlphaMode;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoAlphaMode {
|
||||
match *self {
|
||||
VideoAlphaMode::Copy => gst_video_sys::GST_VIDEO_ALPHA_MODE_COPY,
|
||||
VideoAlphaMode::Set => gst_video_sys::GST_VIDEO_ALPHA_MODE_SET,
|
||||
VideoAlphaMode::Mult => gst_video_sys::GST_VIDEO_ALPHA_MODE_MULT,
|
||||
VideoAlphaMode::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoAlphaMode> for VideoAlphaMode {
|
||||
fn from_glib(value: gst_video_sys::GstVideoAlphaMode) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoAlphaMode::Copy,
|
||||
1 => VideoAlphaMode::Set,
|
||||
2 => VideoAlphaMode::Mult,
|
||||
value => VideoAlphaMode::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoAlphaMode {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_alpha_mode_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoAlphaMode {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoAlphaMode {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoAlphaMode {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_16", feature = "dox"))]
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoCaptionType {
|
||||
|
@ -85,6 +145,69 @@ impl SetValue for VideoCaptionType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoChromaMode {
|
||||
Full,
|
||||
UpsampleOnly,
|
||||
DownsampleOnly,
|
||||
None,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoChromaMode {
|
||||
type GlibType = gst_video_sys::GstVideoChromaMode;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoChromaMode {
|
||||
match *self {
|
||||
VideoChromaMode::Full => gst_video_sys::GST_VIDEO_CHROMA_MODE_FULL,
|
||||
VideoChromaMode::UpsampleOnly => gst_video_sys::GST_VIDEO_CHROMA_MODE_UPSAMPLE_ONLY,
|
||||
VideoChromaMode::DownsampleOnly => gst_video_sys::GST_VIDEO_CHROMA_MODE_DOWNSAMPLE_ONLY,
|
||||
VideoChromaMode::None => gst_video_sys::GST_VIDEO_CHROMA_MODE_NONE,
|
||||
VideoChromaMode::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoChromaMode> for VideoChromaMode {
|
||||
fn from_glib(value: gst_video_sys::GstVideoChromaMode) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoChromaMode::Full,
|
||||
1 => VideoChromaMode::UpsampleOnly,
|
||||
2 => VideoChromaMode::DownsampleOnly,
|
||||
3 => VideoChromaMode::None,
|
||||
value => VideoChromaMode::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoChromaMode {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_chroma_mode_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoChromaMode {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoChromaMode {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoChromaMode {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoColorMatrix {
|
||||
Unknown,
|
||||
|
@ -247,6 +370,72 @@ impl SetValue for VideoColorPrimaries {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoDitherMethod {
|
||||
None,
|
||||
Verterr,
|
||||
FloydSteinberg,
|
||||
SierraLite,
|
||||
Bayer,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoDitherMethod {
|
||||
type GlibType = gst_video_sys::GstVideoDitherMethod;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoDitherMethod {
|
||||
match *self {
|
||||
VideoDitherMethod::None => gst_video_sys::GST_VIDEO_DITHER_NONE,
|
||||
VideoDitherMethod::Verterr => gst_video_sys::GST_VIDEO_DITHER_VERTERR,
|
||||
VideoDitherMethod::FloydSteinberg => gst_video_sys::GST_VIDEO_DITHER_FLOYD_STEINBERG,
|
||||
VideoDitherMethod::SierraLite => gst_video_sys::GST_VIDEO_DITHER_SIERRA_LITE,
|
||||
VideoDitherMethod::Bayer => gst_video_sys::GST_VIDEO_DITHER_BAYER,
|
||||
VideoDitherMethod::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoDitherMethod> for VideoDitherMethod {
|
||||
fn from_glib(value: gst_video_sys::GstVideoDitherMethod) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoDitherMethod::None,
|
||||
1 => VideoDitherMethod::Verterr,
|
||||
2 => VideoDitherMethod::FloydSteinberg,
|
||||
3 => VideoDitherMethod::SierraLite,
|
||||
4 => VideoDitherMethod::Bayer,
|
||||
value => VideoDitherMethod::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoDitherMethod {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_dither_method_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoDitherMethod {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoDitherMethod {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoDitherMethod {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_12", feature = "dox"))]
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoFieldOrder {
|
||||
|
@ -625,6 +814,63 @@ impl SetValue for VideoFormat {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoGammaMode {
|
||||
None,
|
||||
Remap,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoGammaMode {
|
||||
type GlibType = gst_video_sys::GstVideoGammaMode;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoGammaMode {
|
||||
match *self {
|
||||
VideoGammaMode::None => gst_video_sys::GST_VIDEO_GAMMA_MODE_NONE,
|
||||
VideoGammaMode::Remap => gst_video_sys::GST_VIDEO_GAMMA_MODE_REMAP,
|
||||
VideoGammaMode::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoGammaMode> for VideoGammaMode {
|
||||
fn from_glib(value: gst_video_sys::GstVideoGammaMode) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoGammaMode::None,
|
||||
1 => VideoGammaMode::Remap,
|
||||
value => VideoGammaMode::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoGammaMode {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_gamma_mode_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoGammaMode {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoGammaMode {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoGammaMode {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoInterlaceMode {
|
||||
Progressive,
|
||||
|
@ -691,6 +937,69 @@ impl SetValue for VideoInterlaceMode {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoMatrixMode {
|
||||
Full,
|
||||
InputOnly,
|
||||
OutputOnly,
|
||||
None,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoMatrixMode {
|
||||
type GlibType = gst_video_sys::GstVideoMatrixMode;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoMatrixMode {
|
||||
match *self {
|
||||
VideoMatrixMode::Full => gst_video_sys::GST_VIDEO_MATRIX_MODE_FULL,
|
||||
VideoMatrixMode::InputOnly => gst_video_sys::GST_VIDEO_MATRIX_MODE_INPUT_ONLY,
|
||||
VideoMatrixMode::OutputOnly => gst_video_sys::GST_VIDEO_MATRIX_MODE_OUTPUT_ONLY,
|
||||
VideoMatrixMode::None => gst_video_sys::GST_VIDEO_MATRIX_MODE_NONE,
|
||||
VideoMatrixMode::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoMatrixMode> for VideoMatrixMode {
|
||||
fn from_glib(value: gst_video_sys::GstVideoMatrixMode) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoMatrixMode::Full,
|
||||
1 => VideoMatrixMode::InputOnly,
|
||||
2 => VideoMatrixMode::OutputOnly,
|
||||
3 => VideoMatrixMode::None,
|
||||
value => VideoMatrixMode::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoMatrixMode {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_matrix_mode_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoMatrixMode {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoMatrixMode {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoMatrixMode {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoMultiviewFramePacking {
|
||||
None,
|
||||
|
@ -894,6 +1203,132 @@ impl SetValue for VideoMultiviewMode {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoPrimariesMode {
|
||||
None,
|
||||
MergeOnly,
|
||||
Fast,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoPrimariesMode {
|
||||
type GlibType = gst_video_sys::GstVideoPrimariesMode;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoPrimariesMode {
|
||||
match *self {
|
||||
VideoPrimariesMode::None => gst_video_sys::GST_VIDEO_PRIMARIES_MODE_NONE,
|
||||
VideoPrimariesMode::MergeOnly => gst_video_sys::GST_VIDEO_PRIMARIES_MODE_MERGE_ONLY,
|
||||
VideoPrimariesMode::Fast => gst_video_sys::GST_VIDEO_PRIMARIES_MODE_FAST,
|
||||
VideoPrimariesMode::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoPrimariesMode> for VideoPrimariesMode {
|
||||
fn from_glib(value: gst_video_sys::GstVideoPrimariesMode) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoPrimariesMode::None,
|
||||
1 => VideoPrimariesMode::MergeOnly,
|
||||
2 => VideoPrimariesMode::Fast,
|
||||
value => VideoPrimariesMode::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoPrimariesMode {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_primaries_mode_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoPrimariesMode {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoPrimariesMode {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoPrimariesMode {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoResamplerMethod {
|
||||
Nearest,
|
||||
Linear,
|
||||
Cubic,
|
||||
Sinc,
|
||||
Lanczos,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for VideoResamplerMethod {
|
||||
type GlibType = gst_video_sys::GstVideoResamplerMethod;
|
||||
|
||||
fn to_glib(&self) -> gst_video_sys::GstVideoResamplerMethod {
|
||||
match *self {
|
||||
VideoResamplerMethod::Nearest => gst_video_sys::GST_VIDEO_RESAMPLER_METHOD_NEAREST,
|
||||
VideoResamplerMethod::Linear => gst_video_sys::GST_VIDEO_RESAMPLER_METHOD_LINEAR,
|
||||
VideoResamplerMethod::Cubic => gst_video_sys::GST_VIDEO_RESAMPLER_METHOD_CUBIC,
|
||||
VideoResamplerMethod::Sinc => gst_video_sys::GST_VIDEO_RESAMPLER_METHOD_SINC,
|
||||
VideoResamplerMethod::Lanczos => gst_video_sys::GST_VIDEO_RESAMPLER_METHOD_LANCZOS,
|
||||
VideoResamplerMethod::__Unknown(value) => value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<gst_video_sys::GstVideoResamplerMethod> for VideoResamplerMethod {
|
||||
fn from_glib(value: gst_video_sys::GstVideoResamplerMethod) -> Self {
|
||||
skip_assert_initialized!();
|
||||
match value {
|
||||
0 => VideoResamplerMethod::Nearest,
|
||||
1 => VideoResamplerMethod::Linear,
|
||||
2 => VideoResamplerMethod::Cubic,
|
||||
3 => VideoResamplerMethod::Sinc,
|
||||
4 => VideoResamplerMethod::Lanczos,
|
||||
value => VideoResamplerMethod::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for VideoResamplerMethod {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(gst_video_sys::gst_video_resampler_method_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValueOptional<'a> for VideoResamplerMethod {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromValue<'a> for VideoResamplerMethod {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl SetValue for VideoResamplerMethod {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum VideoTileMode {
|
||||
Unknown,
|
||||
|
|
|
@ -21,16 +21,23 @@ pub use self::video_overlay::VideoOverlayExt;
|
|||
pub use self::video_overlay::{VideoOverlay, NONE_VIDEO_OVERLAY};
|
||||
|
||||
mod enums;
|
||||
pub use self::enums::VideoAlphaMode;
|
||||
#[cfg(any(feature = "v1_16", feature = "dox"))]
|
||||
pub use self::enums::VideoCaptionType;
|
||||
pub use self::enums::VideoChromaMode;
|
||||
pub use self::enums::VideoColorMatrix;
|
||||
pub use self::enums::VideoColorPrimaries;
|
||||
pub use self::enums::VideoDitherMethod;
|
||||
#[cfg(any(feature = "v1_12", feature = "dox"))]
|
||||
pub use self::enums::VideoFieldOrder;
|
||||
pub use self::enums::VideoFormat;
|
||||
pub use self::enums::VideoGammaMode;
|
||||
pub use self::enums::VideoInterlaceMode;
|
||||
pub use self::enums::VideoMatrixMode;
|
||||
pub use self::enums::VideoMultiviewFramePacking;
|
||||
pub use self::enums::VideoMultiviewMode;
|
||||
pub use self::enums::VideoPrimariesMode;
|
||||
pub use self::enums::VideoResamplerMethod;
|
||||
pub use self::enums::VideoTileMode;
|
||||
pub use self::enums::VideoTransferFunction;
|
||||
|
||||
|
|
|
@ -107,6 +107,35 @@ unsafe fn convert_sample_async_unsafe<F>(
|
|||
);
|
||||
}
|
||||
|
||||
pub fn convert_sample_future(
|
||||
sample: &gst::Sample,
|
||||
caps: &gst::Caps,
|
||||
timeout: gst::ClockTime,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<gst::Sample, glib::Error>> + 'static>>
|
||||
{
|
||||
use futures_channel::oneshot;
|
||||
use futures_util::future::lazy;
|
||||
use futures_util::future::FutureExt;
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
|
||||
let sample = sample.clone();
|
||||
let caps = caps.clone();
|
||||
let future = lazy(move |_| {
|
||||
assert!(
|
||||
glib::MainContext::ref_thread_default().is_owner(),
|
||||
"Spawning futures only allowed if the thread is owning the MainContext"
|
||||
);
|
||||
|
||||
convert_sample_async(&sample, &caps, timeout, move |res| {
|
||||
let _ = sender.send(res);
|
||||
});
|
||||
})
|
||||
.then(|_| receiver.map(|res| res.expect("Sender dropped before callback was called")));
|
||||
|
||||
Box::pin(future)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -156,7 +185,6 @@ mod tests {
|
|||
l.run();
|
||||
|
||||
let res = res_store.lock().unwrap().take().unwrap();
|
||||
assert!(res.is_ok(), "Error {}", res.unwrap_err());
|
||||
let res = res.unwrap();
|
||||
|
||||
let converted_out_caps = res.get_caps().unwrap();
|
||||
|
|
|
@ -18,6 +18,8 @@ extern crate glib_sys;
|
|||
extern crate gobject_sys;
|
||||
#[macro_use]
|
||||
extern crate gstreamer as gst;
|
||||
extern crate futures_channel;
|
||||
extern crate futures_util;
|
||||
extern crate gstreamer_base as gst_base;
|
||||
extern crate gstreamer_base_sys as gst_base_sys;
|
||||
extern crate gstreamer_sys as gst_sys;
|
||||
|
@ -75,6 +77,8 @@ pub use video_buffer_pool::{
|
|||
BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META,
|
||||
BUFFER_POOL_OPTION_VIDEO_META,
|
||||
};
|
||||
pub mod video_converter;
|
||||
pub use video_converter::{VideoConverter, VideoConverterConfig};
|
||||
|
||||
mod video_codec_frame;
|
||||
mod video_decoder;
|
||||
|
|
|
@ -58,6 +58,14 @@ pub trait VideoDecoderImpl: VideoDecoderImplExt + ElementImpl + Send + Sync + 's
|
|||
self.parent_set_format(element, state)
|
||||
}
|
||||
|
||||
fn set_format_static(
|
||||
&self,
|
||||
element: &VideoDecoder,
|
||||
state: &VideoCodecState<'static, Readable>,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.set_format(element, state)
|
||||
}
|
||||
|
||||
fn parse(
|
||||
&self,
|
||||
element: &VideoDecoder,
|
||||
|
@ -671,7 +679,7 @@ where
|
|||
let wrap_state = VideoCodecState::<Readable>::new(state);
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), false, {
|
||||
match imp.set_format(&wrap, &wrap_state) {
|
||||
match imp.set_format_static(&wrap, &wrap_state) {
|
||||
Ok(()) => true,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
|
|
|
@ -53,6 +53,14 @@ pub trait VideoEncoderImpl: VideoEncoderImplExt + ElementImpl + Send + Sync + 's
|
|||
self.parent_set_format(element, state)
|
||||
}
|
||||
|
||||
fn set_format_static(
|
||||
&self,
|
||||
element: &VideoEncoder,
|
||||
state: &VideoCodecState<'static, Readable>,
|
||||
) -> Result<(), gst::LoggableError> {
|
||||
self.set_format(element, state)
|
||||
}
|
||||
|
||||
fn handle_frame(
|
||||
&self,
|
||||
element: &VideoEncoder,
|
||||
|
@ -588,7 +596,7 @@ where
|
|||
let wrap_state = VideoCodecState::<Readable>::new(state);
|
||||
|
||||
gst_panic_to_error!(&wrap, &instance.panicked(), false, {
|
||||
match imp.set_format(&wrap, &wrap_state) {
|
||||
match imp.set_format_static(&wrap, &wrap_state) {
|
||||
Ok(()) => true,
|
||||
Err(err) => {
|
||||
err.log_with_object(&wrap);
|
||||
|
|
399
gstreamer-video/src/video_converter.rs
Normal file
399
gstreamer-video/src/video_converter.rs
Normal file
|
@ -0,0 +1,399 @@
|
|||
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use gst_video_sys;
|
||||
|
||||
use glib;
|
||||
use glib::translate::ToGlibPtr;
|
||||
use gst;
|
||||
|
||||
use std::ops;
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VideoConverter(ptr::NonNull<gst_video_sys::GstVideoConverter>);
|
||||
|
||||
impl Drop for VideoConverter {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gst_video_sys::gst_video_converter_free(self.0.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for VideoConverter {}
|
||||
unsafe impl Sync for VideoConverter {}
|
||||
|
||||
impl VideoConverter {
|
||||
pub fn new(
|
||||
in_info: &::VideoInfo,
|
||||
out_info: &::VideoInfo,
|
||||
config: Option<VideoConverterConfig>,
|
||||
) -> Result<Self, glib::BoolError> {
|
||||
if in_info.fps() != out_info.fps() {
|
||||
return Err(glib_bool_error!("Can't do framerate conversion"));
|
||||
}
|
||||
|
||||
if in_info.interlace_mode() != out_info.interlace_mode() {
|
||||
return Err(glib_bool_error!("Can't do interlacing conversion"));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = gst_video_sys::gst_video_converter_new(
|
||||
in_info.to_glib_none().0 as *mut _,
|
||||
out_info.to_glib_none().0 as *mut _,
|
||||
config.map(|s| s.0.into_ptr()).unwrap_or(ptr::null_mut()),
|
||||
);
|
||||
if ptr.is_null() {
|
||||
Err(glib_bool_error!("Failed to create video converter"))
|
||||
} else {
|
||||
Ok(VideoConverter(ptr::NonNull::new_unchecked(ptr)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_config(&self) -> VideoConverterConfig {
|
||||
unsafe {
|
||||
VideoConverterConfig(
|
||||
gst::StructureRef::from_glib_borrow(gst_video_sys::gst_video_converter_get_config(
|
||||
self.0.as_ptr(),
|
||||
))
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_config(&mut self, config: VideoConverterConfig) {
|
||||
unsafe {
|
||||
gst_video_sys::gst_video_converter_set_config(self.0.as_ptr(), config.0.into_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<T>(
|
||||
&self,
|
||||
src: &::VideoFrame<T>,
|
||||
dest: &mut ::VideoFrame<::video_frame::Writable>,
|
||||
) {
|
||||
unsafe {
|
||||
gst_video_sys::gst_video_converter_frame(
|
||||
self.0.as_ptr(),
|
||||
src.as_ptr(),
|
||||
dest.as_mut_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame_ref<T>(
|
||||
&self,
|
||||
src: &::VideoFrameRef<T>,
|
||||
dest: &mut ::VideoFrameRef<&mut gst::BufferRef>,
|
||||
) {
|
||||
unsafe {
|
||||
gst_video_sys::gst_video_converter_frame(
|
||||
self.0.as_ptr(),
|
||||
src.as_ptr(),
|
||||
dest.as_mut_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct VideoConverterConfig(gst::Structure);
|
||||
|
||||
impl ops::Deref for VideoConverterConfig {
|
||||
type Target = gst::StructureRef;
|
||||
|
||||
fn deref(&self) -> &gst::StructureRef {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DerefMut for VideoConverterConfig {
|
||||
fn deref_mut(&mut self) -> &mut gst::StructureRef {
|
||||
self.0.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<gst::StructureRef> for VideoConverterConfig {
|
||||
fn as_ref(&self) -> &gst::StructureRef {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<gst::StructureRef> for VideoConverterConfig {
|
||||
fn as_mut(&mut self) -> &mut gst::StructureRef {
|
||||
self.0.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VideoConverterConfig {
|
||||
fn default() -> Self {
|
||||
VideoConverterConfig::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoConverterConfig {
|
||||
pub fn new() -> Self {
|
||||
VideoConverterConfig(gst::Structure::new_empty("GstVideoConverter"))
|
||||
}
|
||||
|
||||
pub fn set_resampler_method(&mut self, v: ::VideoResamplerMethod) {
|
||||
self.0.set("GstVideoConverter.resampler-method", &v);
|
||||
}
|
||||
|
||||
pub fn get_resampler_method(&self) -> ::VideoResamplerMethod {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.resampler-method")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoResamplerMethod::Cubic)
|
||||
}
|
||||
|
||||
pub fn set_chroma_resampler_method(&mut self, v: ::VideoResamplerMethod) {
|
||||
self.0.set("GstVideoConverter.chroma-resampler-method", &v);
|
||||
}
|
||||
|
||||
pub fn get_chroma_resampler_method(&self) -> ::VideoResamplerMethod {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.chroma-resampler-method")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoResamplerMethod::Linear)
|
||||
}
|
||||
|
||||
pub fn set_resampler_taps(&mut self, v: u32) {
|
||||
self.0.set("GstVideoConverter.resampler-taps", &v);
|
||||
}
|
||||
|
||||
pub fn get_resampler_taps(&self) -> u32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.resampler-taps")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn set_dither_method(&mut self, v: ::VideoDitherMethod) {
|
||||
self.0.set("GstVideoConverter.dither-method", &v);
|
||||
}
|
||||
|
||||
pub fn get_dither_method(&self) -> ::VideoDitherMethod {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.dither-method")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoDitherMethod::Bayer)
|
||||
}
|
||||
|
||||
pub fn set_dither_quantization(&mut self, v: u32) {
|
||||
self.0.set("GstVideoConverter.dither-quantization", &v);
|
||||
}
|
||||
|
||||
pub fn get_dither_quantization(&self) -> u32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.dither-quantization")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
pub fn set_src_x(&mut self, v: i32) {
|
||||
self.0.set("GstVideoConverter.src-x", &v);
|
||||
}
|
||||
|
||||
pub fn get_src_x(&self) -> i32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.src-x")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn set_src_y(&mut self, v: i32) {
|
||||
self.0.set("GstVideoConverter.src-y", &v);
|
||||
}
|
||||
|
||||
pub fn get_src_y(&self) -> i32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.src-y")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn set_src_width(&mut self, v: Option<i32>) {
|
||||
if let Some(v) = v {
|
||||
self.0.set("GstVideoConverter.src-width", &v);
|
||||
} else {
|
||||
self.0.remove_field("GstVideoConverter.src-width");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_src_width(&self) -> Option<i32> {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.src-width")
|
||||
.expect("Wrong type")
|
||||
}
|
||||
|
||||
pub fn set_src_height(&mut self, v: Option<i32>) {
|
||||
if let Some(v) = v {
|
||||
self.0.set("GstVideoConverter.src-height", &v);
|
||||
} else {
|
||||
self.0.remove_field("GstVideoConverter.src-height");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_src_height(&self) -> Option<i32> {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.src-height")
|
||||
.expect("Wrong type")
|
||||
}
|
||||
|
||||
pub fn set_dest_x(&mut self, v: i32) {
|
||||
self.0.set("GstVideoConverter.dest-x", &v);
|
||||
}
|
||||
|
||||
pub fn get_dest_x(&self) -> i32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.dest-x")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn set_dest_y(&mut self, v: i32) {
|
||||
self.0.set("GstVideoConverter.dest-y", &v);
|
||||
}
|
||||
|
||||
pub fn get_dest_y(&self) -> i32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.dest-y")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn set_dest_width(&mut self, v: Option<i32>) {
|
||||
if let Some(v) = v {
|
||||
self.0.set("GstVideoConverter.dest-width", &v);
|
||||
} else {
|
||||
self.0.remove_field("GstVideoConverter.dest-width");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dest_width(&self) -> Option<i32> {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.dest-width")
|
||||
.expect("Wrong type")
|
||||
}
|
||||
|
||||
pub fn set_dest_height(&mut self, v: Option<i32>) {
|
||||
if let Some(v) = v {
|
||||
self.0.set("GstVideoConverter.dest-height", &v);
|
||||
} else {
|
||||
self.0.remove_field("GstVideoConverter.dest-height");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dest_height(&self) -> Option<i32> {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.dest-height")
|
||||
.expect("Wrong type")
|
||||
}
|
||||
|
||||
pub fn set_fill_border(&mut self, v: bool) {
|
||||
self.0.set("GstVideoConverter.fill-border", &v);
|
||||
}
|
||||
|
||||
pub fn get_fill_border(&self) -> bool {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.fill-border")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
pub fn set_alpha_value(&mut self, v: f64) {
|
||||
self.0.set("GstVideoConverter.alpha-value", &v);
|
||||
}
|
||||
|
||||
pub fn get_alpha_value(&self) -> f64 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.alpha-value")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(1.0)
|
||||
}
|
||||
|
||||
pub fn set_alpha_mode(&mut self, v: ::VideoAlphaMode) {
|
||||
self.0.set("GstVideoConverter.alpha-mode", &v);
|
||||
}
|
||||
|
||||
pub fn get_alpha_mode(&self) -> ::VideoAlphaMode {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.alpha-mode")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoAlphaMode::Copy)
|
||||
}
|
||||
|
||||
pub fn set_border_argb(&mut self, v: u32) {
|
||||
self.0.set("GstVideoConverter.border-argb", &v);
|
||||
}
|
||||
|
||||
pub fn get_border_argb(&self) -> u32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.border-argb")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(0xff_00_00_00)
|
||||
}
|
||||
|
||||
pub fn set_chroma_mode(&mut self, v: ::VideoChromaMode) {
|
||||
self.0.set("GstVideoConverter.chroma-mode", &v);
|
||||
}
|
||||
|
||||
pub fn get_chroma_mode(&self) -> ::VideoChromaMode {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.chroma-mode")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoChromaMode::Full)
|
||||
}
|
||||
|
||||
pub fn set_matrix_mode(&mut self, v: ::VideoMatrixMode) {
|
||||
self.0.set("GstVideoConverter.matrix-mode", &v);
|
||||
}
|
||||
|
||||
pub fn get_matrix_mode(&self) -> ::VideoMatrixMode {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.matrix-mode")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoMatrixMode::Full)
|
||||
}
|
||||
|
||||
pub fn set_gamma_mode(&mut self, v: ::VideoGammaMode) {
|
||||
self.0.set("GstVideoConverter.gamma-mode", &v);
|
||||
}
|
||||
|
||||
pub fn get_gamma_mode(&self) -> ::VideoGammaMode {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.gamma-mode")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoGammaMode::None)
|
||||
}
|
||||
|
||||
pub fn set_primaries_mode(&mut self, v: ::VideoPrimariesMode) {
|
||||
self.0.set("GstVideoConverter.primaries-mode", &v);
|
||||
}
|
||||
|
||||
pub fn get_primaries_mode(&self) -> ::VideoPrimariesMode {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.primaries-mode")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(::VideoPrimariesMode::None)
|
||||
}
|
||||
|
||||
pub fn set_threads(&mut self, v: u32) {
|
||||
self.0.set("GstVideoConverter.threads", &v);
|
||||
}
|
||||
|
||||
pub fn get_threads(&self) -> u32 {
|
||||
self.0
|
||||
.get_optional("GstVideoConverter.threads")
|
||||
.expect("Wrong type")
|
||||
.unwrap_or(1)
|
||||
}
|
||||
}
|
|
@ -57,7 +57,7 @@ pub trait VideoDecoderExtManual: 'static {
|
|||
fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime);
|
||||
fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime);
|
||||
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<Readable>>;
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<'static, Readable>>;
|
||||
fn set_output_state(
|
||||
&self,
|
||||
fmt: VideoFormat,
|
||||
|
@ -233,7 +233,7 @@ impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<Readable>> {
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
|
||||
let state = unsafe {
|
||||
gst_video_sys::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0)
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ pub trait VideoEncoderExtManual: 'static {
|
|||
fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime);
|
||||
fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime);
|
||||
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<Readable>>;
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<'static, Readable>>;
|
||||
fn set_output_state(
|
||||
&self,
|
||||
caps: gst::Caps,
|
||||
|
@ -166,7 +166,7 @@ impl<O: IsA<VideoEncoder>> VideoEncoderExtManual for O {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<Readable>> {
|
||||
fn get_output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
|
||||
let state = unsafe {
|
||||
gst_video_sys::gst_video_encoder_get_output_state(self.as_ref().to_glib_none().0)
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ use glib::translate::{from_glib, ToGlibPtr};
|
|||
use gst;
|
||||
use gst::miniobject::MiniObject;
|
||||
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops;
|
||||
|
@ -23,37 +24,50 @@ use std::slice;
|
|||
pub enum Readable {}
|
||||
pub enum Writable {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VideoFrame<T>(
|
||||
gst_video_sys::GstVideoFrame,
|
||||
Option<gst::Buffer>,
|
||||
::VideoInfo,
|
||||
PhantomData<T>,
|
||||
);
|
||||
pub struct VideoFrame<T> {
|
||||
frame: gst_video_sys::GstVideoFrame,
|
||||
buffer: Option<gst::Buffer>,
|
||||
info: ::VideoInfo,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for VideoFrame<T> {}
|
||||
unsafe impl<T> Sync for VideoFrame<T> {}
|
||||
|
||||
impl<T> fmt::Debug for VideoFrame<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("VideoFrame")
|
||||
.field("frame", &self.frame)
|
||||
.field("buffer", &self.buffer)
|
||||
.field("info", &self.info)
|
||||
.field("phantom", &self.phantom)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VideoFrame<T> {
|
||||
pub fn info(&self) -> &::VideoInfo {
|
||||
&self.2
|
||||
&self.info
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> ::VideoFrameFlags {
|
||||
from_glib(self.0.flags)
|
||||
from_glib(self.frame.flags)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> i32 {
|
||||
self.0.id
|
||||
self.frame.id
|
||||
}
|
||||
|
||||
pub fn into_buffer(mut self) -> gst::Buffer {
|
||||
self.1.take().unwrap()
|
||||
self.buffer.take().unwrap()
|
||||
}
|
||||
|
||||
pub fn copy(&self, dest: &mut VideoFrame<Writable>) -> Result<(), glib::BoolError> {
|
||||
unsafe {
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_copy(&mut dest.0, &self.0));
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_copy(
|
||||
&mut dest.frame,
|
||||
&self.frame,
|
||||
));
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -71,8 +85,8 @@ impl<T> VideoFrame<T> {
|
|||
|
||||
unsafe {
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_copy_plane(
|
||||
&mut dest.0,
|
||||
&self.0,
|
||||
&mut dest.frame,
|
||||
&self.frame,
|
||||
plane,
|
||||
));
|
||||
if res {
|
||||
|
@ -136,7 +150,7 @@ impl<T> VideoFrame<T> {
|
|||
}
|
||||
|
||||
pub fn buffer(&self) -> &gst::BufferRef {
|
||||
unsafe { gst::BufferRef::from_ptr(self.0.buffer) }
|
||||
unsafe { gst::BufferRef::from_ptr(self.frame.buffer) }
|
||||
}
|
||||
|
||||
pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
|
||||
|
@ -149,7 +163,10 @@ impl<T> VideoFrame<T> {
|
|||
// Just get the palette
|
||||
if format_info.has_palette() && plane == 1 {
|
||||
unsafe {
|
||||
return Ok(slice::from_raw_parts(self.0.data[1] as *const u8, 256 * 4));
|
||||
return Ok(slice::from_raw_parts(
|
||||
self.frame.data[1] as *const u8,
|
||||
256 * 4,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +177,7 @@ impl<T> VideoFrame<T> {
|
|||
|
||||
unsafe {
|
||||
Ok(slice::from_raw_parts(
|
||||
self.0.data[plane as usize] as *const u8,
|
||||
self.frame.data[plane as usize] as *const u8,
|
||||
(w * h) as usize,
|
||||
))
|
||||
}
|
||||
|
@ -169,14 +186,34 @@ impl<T> VideoFrame<T> {
|
|||
pub unsafe fn from_glib_full(frame: gst_video_sys::GstVideoFrame) -> Self {
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
let buffer = gst::Buffer::from_glib_none(frame.buffer);
|
||||
VideoFrame(frame, Some(buffer), info, PhantomData)
|
||||
VideoFrame {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_video_frame_ref(&self) -> VideoFrameRef<&gst::BufferRef> {
|
||||
let frame = unsafe { ptr::read(&self.frame) };
|
||||
let info = self.info.clone();
|
||||
VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(self.buffer()),
|
||||
info,
|
||||
borrowed: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const gst_video_sys::GstVideoFrame {
|
||||
&self.frame
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for VideoFrame<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gst_video_sys::gst_video_frame_unmap(&mut self.0);
|
||||
gst_video_sys::gst_video_frame_unmap(&mut self.frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +239,12 @@ impl VideoFrame<Readable> {
|
|||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrame(frame, Some(buffer), info, PhantomData))
|
||||
Ok(VideoFrame {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,20 +271,15 @@ impl VideoFrame<Readable> {
|
|||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrame(frame, Some(buffer), info, PhantomData))
|
||||
Ok(VideoFrame {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_video_frame_ref(&self) -> VideoFrameRef<&gst::BufferRef> {
|
||||
let vframe = unsafe { ptr::read(&self.0) };
|
||||
let info = self.2.clone();
|
||||
VideoFrameRef(vframe, Some(self.buffer()), info, true)
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const gst_video_sys::GstVideoFrame {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFrame<Writable> {
|
||||
|
@ -268,7 +305,12 @@ impl VideoFrame<Writable> {
|
|||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrame(frame, Some(buffer), info, PhantomData))
|
||||
Ok(VideoFrame {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,13 +339,18 @@ impl VideoFrame<Writable> {
|
|||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrame(frame, Some(buffer), info, PhantomData))
|
||||
Ok(VideoFrame {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
|
||||
unsafe { gst::BufferRef::from_mut_ptr(self.0.buffer) }
|
||||
unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) }
|
||||
}
|
||||
|
||||
pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
|
||||
|
@ -317,7 +364,7 @@ impl VideoFrame<Writable> {
|
|||
if format_info.has_palette() && plane == 1 {
|
||||
unsafe {
|
||||
return Ok(slice::from_raw_parts_mut(
|
||||
self.0.data[1] as *mut u8,
|
||||
self.frame.data[1] as *mut u8,
|
||||
256 * 4,
|
||||
));
|
||||
}
|
||||
|
@ -330,102 +377,47 @@ impl VideoFrame<Writable> {
|
|||
|
||||
unsafe {
|
||||
Ok(slice::from_raw_parts_mut(
|
||||
self.0.data[plane as usize] as *mut u8,
|
||||
self.frame.data[plane as usize] as *mut u8,
|
||||
(w * h) as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_video_frame_ref(&mut self) -> VideoFrameRef<&mut gst::BufferRef> {
|
||||
let vframe = unsafe { ptr::read(&self.0) };
|
||||
let info = self.2.clone();
|
||||
VideoFrameRef(vframe, Some(self.buffer_mut()), info, true)
|
||||
let frame = unsafe { ptr::read(&self.frame) };
|
||||
let info = self.info.clone();
|
||||
VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(self.buffer_mut()),
|
||||
info,
|
||||
borrowed: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut gst_video_sys::GstVideoFrame {
|
||||
&mut self.0
|
||||
&mut self.frame
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VideoFrameRef<T>(gst_video_sys::GstVideoFrame, Option<T>, ::VideoInfo, bool);
|
||||
|
||||
impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
||||
pub fn as_ptr(&self) -> *const gst_video_sys::GstVideoFrame {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub unsafe fn from_glib_borrow(frame: *const gst_video_sys::GstVideoFrame) -> Self {
|
||||
assert!(!frame.is_null());
|
||||
|
||||
let frame = ptr::read(frame);
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
let buffer = gst::BufferRef::from_ptr(frame.buffer);
|
||||
VideoFrameRef(frame, Some(buffer), info, false)
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_readable<'b>(
|
||||
buffer: &'a gst::BufferRef,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Result<VideoFrameRef<&'a gst::BufferRef>, glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::MaybeUninit::zeroed();
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_map(
|
||||
frame.as_mut_ptr(),
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
gst_video_sys::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst_sys::GST_MAP_READ,
|
||||
));
|
||||
|
||||
if !res {
|
||||
Err(glib_bool_error!("Failed to map VideoFrame"))
|
||||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_id_readable<'b>(
|
||||
buffer: &'a gst::BufferRef,
|
||||
id: i32,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Result<VideoFrameRef<&'a gst::BufferRef>, glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::MaybeUninit::zeroed();
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_map_id(
|
||||
frame.as_mut_ptr(),
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
id,
|
||||
gst_video_sys::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst_sys::GST_MAP_READ,
|
||||
));
|
||||
|
||||
if !res {
|
||||
Err(glib_bool_error!("Failed to map VideoFrame"))
|
||||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct VideoFrameRef<T> {
|
||||
frame: gst_video_sys::GstVideoFrame,
|
||||
buffer: Option<T>,
|
||||
info: ::VideoInfo,
|
||||
borrowed: bool,
|
||||
}
|
||||
|
||||
impl<T> VideoFrameRef<T> {
|
||||
pub fn info(&self) -> &::VideoInfo {
|
||||
&self.2
|
||||
&self.info
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> ::VideoFrameFlags {
|
||||
from_glib(self.0.flags)
|
||||
from_glib(self.frame.flags)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> i32 {
|
||||
self.0.id
|
||||
self.frame.id
|
||||
}
|
||||
|
||||
pub fn copy(
|
||||
|
@ -433,7 +425,10 @@ impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
|||
dest: &mut VideoFrameRef<&mut gst::BufferRef>,
|
||||
) -> Result<(), glib::BoolError> {
|
||||
unsafe {
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_copy(&mut dest.0, &self.0));
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_copy(
|
||||
&mut dest.frame,
|
||||
&self.frame,
|
||||
));
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -451,8 +446,8 @@ impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
|||
|
||||
unsafe {
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_copy_plane(
|
||||
&mut dest.0,
|
||||
&self.0,
|
||||
&mut dest.frame,
|
||||
&self.frame,
|
||||
plane,
|
||||
));
|
||||
if res {
|
||||
|
@ -515,10 +510,6 @@ impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
|||
self.info().offset()
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &gst::BufferRef {
|
||||
self.1.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
|
||||
if plane >= self.n_planes() {
|
||||
return Err(glib_bool_error!("Plane index higher than number of planes"));
|
||||
|
@ -529,7 +520,10 @@ impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
|||
// Just get the palette
|
||||
if format_info.has_palette() && plane == 1 {
|
||||
unsafe {
|
||||
return Ok(slice::from_raw_parts(self.0.data[1] as *const u8, 256 * 4));
|
||||
return Ok(slice::from_raw_parts(
|
||||
self.frame.data[1] as *const u8,
|
||||
256 * 4,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,11 +534,97 @@ impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
|||
|
||||
unsafe {
|
||||
Ok(slice::from_raw_parts(
|
||||
self.0.data[plane as usize] as *const u8,
|
||||
self.frame.data[plane as usize] as *const u8,
|
||||
(w * h) as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const gst_video_sys::GstVideoFrame {
|
||||
&self.frame
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
||||
pub unsafe fn from_glib_borrow(frame: *const gst_video_sys::GstVideoFrame) -> Self {
|
||||
assert!(!frame.is_null());
|
||||
|
||||
let frame = ptr::read(frame);
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
let buffer = gst::BufferRef::from_ptr(frame.buffer);
|
||||
VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
borrowed: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_readable<'b>(
|
||||
buffer: &'a gst::BufferRef,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Result<VideoFrameRef<&'a gst::BufferRef>, glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::MaybeUninit::zeroed();
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_map(
|
||||
frame.as_mut_ptr(),
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
gst_video_sys::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst_sys::GST_MAP_READ,
|
||||
));
|
||||
|
||||
if !res {
|
||||
Err(glib_bool_error!("Failed to map VideoFrame"))
|
||||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
borrowed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_id_readable<'b>(
|
||||
buffer: &'a gst::BufferRef,
|
||||
id: i32,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Result<VideoFrameRef<&'a gst::BufferRef>, glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::MaybeUninit::zeroed();
|
||||
let res: bool = from_glib(gst_video_sys::gst_video_frame_map_id(
|
||||
frame.as_mut_ptr(),
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
id,
|
||||
gst_video_sys::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst_sys::GST_MAP_READ,
|
||||
));
|
||||
|
||||
if !res {
|
||||
Err(glib_bool_error!("Failed to map VideoFrame"))
|
||||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
borrowed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &gst::BufferRef {
|
||||
self.buffer.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
||||
|
@ -554,7 +634,12 @@ impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
|||
let frame = ptr::read(frame);
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
let buffer = gst::BufferRef::from_mut_ptr(frame.buffer);
|
||||
VideoFrameRef(frame, Some(buffer), info, false)
|
||||
VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
borrowed: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_writable<'b>(
|
||||
|
@ -579,7 +664,12 @@ impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
|||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
Ok(VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
borrowed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -608,13 +698,18 @@ impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
|||
} else {
|
||||
let frame = frame.assume_init();
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Ok(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
Ok(VideoFrameRef {
|
||||
frame,
|
||||
buffer: Some(buffer),
|
||||
info,
|
||||
borrowed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
|
||||
self.1.as_mut().unwrap()
|
||||
self.buffer.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
|
||||
|
@ -628,7 +723,7 @@ impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
|||
if format_info.has_palette() && plane == 1 {
|
||||
unsafe {
|
||||
return Ok(slice::from_raw_parts_mut(
|
||||
self.0.data[1] as *mut u8,
|
||||
self.frame.data[1] as *mut u8,
|
||||
256 * 4,
|
||||
));
|
||||
}
|
||||
|
@ -641,14 +736,14 @@ impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
|||
|
||||
unsafe {
|
||||
Ok(slice::from_raw_parts_mut(
|
||||
self.0.data[plane as usize] as *mut u8,
|
||||
self.frame.data[plane as usize] as *mut u8,
|
||||
(w * h) as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut gst_video_sys::GstVideoFrame {
|
||||
&mut self.0
|
||||
&mut self.frame
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,9 +763,9 @@ unsafe impl<T> Sync for VideoFrameRef<T> {}
|
|||
|
||||
impl<T> Drop for VideoFrameRef<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.3 {
|
||||
if !self.borrowed {
|
||||
unsafe {
|
||||
gst_video_sys::gst_video_frame_unmap(&mut self.0);
|
||||
gst_video_sys::gst_video_frame_unmap(&mut self.frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,7 +267,38 @@ impl<'a> VideoInfoBuilder<'a> {
|
|||
unsafe {
|
||||
let mut info = mem::MaybeUninit::uninit();
|
||||
|
||||
#[cfg(not(feature = "v1_16"))]
|
||||
#[cfg(not(feature = "v1_12"))]
|
||||
let res: bool = {
|
||||
// The bool return value is new with 1.11.1, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/commit/17cdd369e6f2f73329d27dfceb50011f40f1ceb0
|
||||
let res = if gst::version() < (1, 11, 1, 0) {
|
||||
gst_video_sys::gst_video_info_set_format(
|
||||
info.as_mut_ptr(),
|
||||
self.format.to_glib(),
|
||||
self.width,
|
||||
self.height,
|
||||
);
|
||||
|
||||
true
|
||||
} else {
|
||||
from_glib(gst_video_sys::gst_video_info_set_format(
|
||||
info.as_mut_ptr(),
|
||||
self.format.to_glib(),
|
||||
self.width,
|
||||
self.height,
|
||||
))
|
||||
};
|
||||
|
||||
if res {
|
||||
if let Some(interlace_mode) = self.interlace_mode {
|
||||
let info = info.as_mut_ptr();
|
||||
(*info).interlace_mode = interlace_mode.to_glib();
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
};
|
||||
#[cfg(all(feature = "v1_12", not(feature = "v1_16")))]
|
||||
let res: bool = {
|
||||
let res = from_glib(gst_video_sys::gst_video_info_set_format(
|
||||
info.as_mut_ptr(),
|
||||
|
@ -710,8 +741,23 @@ impl VideoInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_12", feature = "dox"))]
|
||||
pub fn align(&mut self, align: &mut ::VideoAlignment) -> bool {
|
||||
#[cfg(not(feature = "v1_12"))]
|
||||
unsafe {
|
||||
// The bool return value is new with 1.11.1, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/commit/17cdd369e6f2f73329d27dfceb50011f40f1ceb0
|
||||
if gst::version() < (1, 11, 1, 0) {
|
||||
gst_video_sys::gst_video_info_align(&mut self.0, &mut align.0);
|
||||
|
||||
true
|
||||
} else {
|
||||
from_glib(gst_video_sys::gst_video_info_align(
|
||||
&mut self.0,
|
||||
&mut align.0,
|
||||
))
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "v1_12")]
|
||||
unsafe {
|
||||
from_glib(gst_video_sys::gst_video_info_align(
|
||||
&mut self.0,
|
||||
|
@ -973,13 +1019,13 @@ mod tests {
|
|||
.expect("Failed to create VideoInfo");
|
||||
|
||||
assert_eq!(info.stride(), [1920, 1920]);
|
||||
assert_eq!(info.offset(), [0, 2073600]);
|
||||
assert_eq!(info.offset(), [0, 2_073_600]);
|
||||
|
||||
let mut align = ::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
|
||||
assert!(info.align(&mut align));
|
||||
|
||||
assert_eq!(info.stride(), [1928, 1928]);
|
||||
assert_eq!(info.offset(), [0, 2082240]);
|
||||
assert_eq!(info.offset(), [0, 2_082_240]);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_12", feature = "dox"))]
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-webrtc"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer WebRTC library"
|
||||
|
@ -14,13 +14,13 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
gstreamer-webrtc-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer", features = ["v1_14"] }
|
||||
gstreamer-sdp = { path = "../gstreamer-sdp", features = ["v1_14"] }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
gstreamer-webrtc-sys = { version = "0.8" }
|
||||
glib = { version = "0.9" }
|
||||
gstreamer = { version = "0.15", path = "../gstreamer", features = ["v1_14"] }
|
||||
gstreamer-sdp = { version = "0.15", path = "../gstreamer-sdp", features = ["v1_14"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustdoc-stripper = { version = "0.1", optional = true }
|
||||
|
|
|
@ -5,6 +5,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.15.4] - 2020-03-09
|
||||
### Fixed
|
||||
- Allow logging any `glib::Object` and not just `gst::Object`
|
||||
- Fix floating reference handling in `RTSPMedia::take_pipeline()`
|
||||
- Hold `GMutex` guards for the remainder of the function and warn if they're
|
||||
directly dropped
|
||||
- Work around empty/any caps handling bugs in `Caps::fixate()`
|
||||
|
||||
### Added
|
||||
- Add `BaseTransform::prepare_output_buffer()` subclassing support
|
||||
- `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing
|
||||
support
|
||||
- Handle panicking in `appsrc`/`appsink` callbacks by posting an error message
|
||||
instead of killing the process
|
||||
|
||||
## [0.15.3] - 2020-02-15
|
||||
### Fixed
|
||||
- `UniqueFlowCombiner::clear()` should take a mutable reference.
|
||||
- `AudioStreamAlign` doesn't require mutable references for getters anymore.
|
||||
- Don't use bool return value of `gst_video_info_set_format()` and
|
||||
`gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back
|
||||
then. We'd otherwise use some random value.
|
||||
- Make `VideoInfo::align()` is available since 1.8.
|
||||
- Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync
|
||||
handler. Before 1.16.3 this was not thread-safe and caused crashes. When
|
||||
running with older versions changing them causes a panic now and unsetting
|
||||
the bus sync handler has not effect. With newer versions it works correctly.
|
||||
|
||||
### Added
|
||||
- Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`.
|
||||
- Add `VideoConverter` bindings.
|
||||
- Add `Future`s variant for `gst::Promise` constructor.
|
||||
- Add `Future`s variant for `gst_video::convert_sample_async()`.
|
||||
- Add `submit_input_buffer()`, `generate_output()`, `before_transform()`,
|
||||
`copy_metadata()` and `transform_meta()` virtual method support for
|
||||
`BaseTransform`.
|
||||
- Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating
|
||||
both into Rust async contexts.
|
||||
|
||||
### Changed
|
||||
- More generic implementations of `VideoFrame` / `VideoFrameRef` functions to
|
||||
allow usage in more generic contexts.
|
||||
|
||||
## [0.15.2] - 2020-01-30
|
||||
### Fixed
|
||||
- Fix another race condition in the `gst::Bus` `Stream` that could cause it to
|
||||
not wake up although a message is available.
|
||||
|
||||
## [0.15.1] - 2020-01-23
|
||||
### Added
|
||||
- Use static inner lifetime for `VideoCodecState<Readable>` so that it can be
|
||||
stored safely on the heap.
|
||||
- Getters/setters for `BinFlags` on `gst::Bin`.
|
||||
- `gst::Caps::builder_full()` for building caps with multiple structures
|
||||
conveniently.
|
||||
- `gst::Element::call_async_future()` for asynchronously spawning a closure
|
||||
and returning a `Future` for awaiting its return value.
|
||||
|
||||
### Fixed
|
||||
- Various clippy warnings.
|
||||
- Getters/setters for `PadFlags` on `gst::Pad` now provide the correct
|
||||
behaviour.
|
||||
- Take mutex before popping messages in the `gst::Bus` `Stream` to close a
|
||||
small race condition that could cause it to not be woken up.
|
||||
- `gst::ChildProxy` implementers do not have to provide `child_added()` and
|
||||
`child_removed()` functions anymore but these are optional now.
|
||||
- Manually implement `Debug` impls for various generic types where to `Debug`
|
||||
impl should not depend on their type parameters also implementing `Debug`.
|
||||
|
||||
## [0.15.0] - 2019-12-18
|
||||
### Added
|
||||
- `StructureRef::get_optional()` for returning `None` if the field does not
|
||||
|
@ -616,7 +685,11 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...HEAD
|
||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...HEAD
|
||||
[0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4
|
||||
[0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3
|
||||
[0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2
|
||||
[0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1
|
||||
[0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0
|
||||
[0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2
|
||||
[0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer"
|
||||
version = "0.15.0"
|
||||
version = "0.15.4"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer"
|
||||
|
@ -16,13 +16,15 @@ build = "build.rs"
|
|||
bitflags = "1.0"
|
||||
cfg-if = "0.1"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
glib-sys = { version = "0.9" }
|
||||
gobject-sys = { version = "0.9" }
|
||||
gstreamer-sys = { version = "0.8", features = ["v1_8"] }
|
||||
glib = { version = "0.9" }
|
||||
num-rational = { version = "0.2", default-features = false, features = [] }
|
||||
lazy_static = "1.0"
|
||||
futures-core = "0.3"
|
||||
futures-util = "0.3"
|
||||
futures-channel = "0.3"
|
||||
muldiv = "0.2"
|
||||
serde = { version = "1.0", optional = true }
|
||||
serde_bytes = { version = "0.11", optional = true }
|
||||
|
@ -35,6 +37,7 @@ rustdoc-stripper = { version = "0.1", optional = true }
|
|||
[dev-dependencies]
|
||||
ron = "0.5"
|
||||
serde_json = "1.0"
|
||||
futures-executor = "0.3.1"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use Bin;
|
||||
use BinFlags;
|
||||
use Element;
|
||||
use LoggableError;
|
||||
|
||||
|
@ -48,6 +49,12 @@ pub trait GstBinExtManual: 'static {
|
|||
details: ::DebugGraphDetails,
|
||||
file_name: Q,
|
||||
);
|
||||
|
||||
fn set_bin_flags(&self, flags: BinFlags);
|
||||
|
||||
fn unset_bin_flags(&self, flags: BinFlags);
|
||||
|
||||
fn get_bin_flags(&self) -> BinFlags;
|
||||
}
|
||||
|
||||
impl<O: IsA<Bin>> GstBinExtManual for O {
|
||||
|
@ -150,7 +157,7 @@ impl<O: IsA<Bin>> GstBinExtManual for O {
|
|||
fn get_children(&self) -> Vec<Element> {
|
||||
unsafe {
|
||||
let bin: &gst_sys::GstBin = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&bin.element.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&bin.element.object.lock);
|
||||
FromGlibPtrContainer::from_glib_none(bin.children)
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +177,30 @@ impl<O: IsA<Bin>> GstBinExtManual for O {
|
|||
) {
|
||||
::debug_bin_to_dot_file_with_ts(self, details, file_name)
|
||||
}
|
||||
|
||||
fn set_bin_flags(&self, flags: BinFlags) {
|
||||
unsafe {
|
||||
let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _;
|
||||
let _guard = ::utils::MutexGuard::lock(&(*ptr).lock);
|
||||
(*ptr).flags |= flags.to_glib();
|
||||
}
|
||||
}
|
||||
|
||||
fn unset_bin_flags(&self, flags: BinFlags) {
|
||||
unsafe {
|
||||
let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _;
|
||||
let _guard = ::utils::MutexGuard::lock(&(*ptr).lock);
|
||||
(*ptr).flags &= !flags.to_glib();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bin_flags(&self) -> BinFlags {
|
||||
unsafe {
|
||||
let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _;
|
||||
let _guard = ::utils::MutexGuard::lock(&(*ptr).lock);
|
||||
from_glib((*ptr).flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn do_latency_trampoline<
|
||||
|
|
|
@ -596,7 +596,6 @@ impl BufferRef {
|
|||
|
||||
macro_rules! define_iter(
|
||||
($name:ident, $typ:ty, $mtyp:ty, $prepare_buffer:expr, $from_ptr:expr) => {
|
||||
#[derive(Debug)]
|
||||
pub struct $name<'a, T: MetaAPI + 'a> {
|
||||
buffer: $typ,
|
||||
state: glib_sys::gpointer,
|
||||
|
@ -607,6 +606,17 @@ macro_rules! define_iter(
|
|||
unsafe impl<'a, T: MetaAPI> Send for $name<'a, T> { }
|
||||
unsafe impl<'a, T: MetaAPI> Sync for $name<'a, T> { }
|
||||
|
||||
impl<'a, T: MetaAPI> fmt::Debug for $name<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct(stringify!($name))
|
||||
.field("buffer", &self.buffer)
|
||||
.field("state", &self.state)
|
||||
.field("meta_api", &self.meta_api)
|
||||
.field("items", &self.items)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: MetaAPI> $name<'a, T> {
|
||||
fn new(buffer: $typ) -> $name<'a, T> {
|
||||
skip_assert_initialized!();
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::mem;
|
|||
use std::ops;
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BufferPoolConfig(Structure);
|
||||
|
||||
impl ops::Deref for BufferPoolConfig {
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use futures_core::stream::Stream;
|
||||
use futures_core::task::{Context, Poll, Waker};
|
||||
use futures_channel::mpsc::{self, UnboundedReceiver};
|
||||
use futures_core::Stream;
|
||||
use futures_util::{future, StreamExt};
|
||||
use glib;
|
||||
use glib::source::{Continue, Priority, SourceId};
|
||||
use glib::translate::*;
|
||||
|
@ -17,14 +18,17 @@ use gst_sys;
|
|||
use std::cell::RefCell;
|
||||
use std::mem::transmute;
|
||||
use std::pin::Pin;
|
||||
use std::ptr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use Bus;
|
||||
use BusSyncReply;
|
||||
use Message;
|
||||
use MessageType;
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_ONCE_QUARK: glib::Quark = glib::Quark::from_string("gstreamer-rs-sync-handler");
|
||||
}
|
||||
|
||||
unsafe extern "C" fn trampoline_watch<F: FnMut(&Bus, &Message) -> Continue + 'static>(
|
||||
bus: *mut gst_sys::GstBus,
|
||||
msg: *mut gst_sys::GstMessage,
|
||||
|
@ -157,8 +161,26 @@ impl Bus {
|
|||
F: Fn(&Bus, &Message) -> BusSyncReply + Send + Sync + 'static,
|
||||
{
|
||||
unsafe {
|
||||
let bus = self.to_glib_none().0;
|
||||
|
||||
// This is not thread-safe before 1.16.3, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/merge_requests/416
|
||||
if ::version() < (1, 16, 3, 0) {
|
||||
if !gobject_sys::g_object_get_qdata(bus as *mut _, SET_ONCE_QUARK.to_glib())
|
||||
.is_null()
|
||||
{
|
||||
panic!("Bus sync handler can only be set once");
|
||||
}
|
||||
|
||||
gobject_sys::g_object_set_qdata(
|
||||
bus as *mut _,
|
||||
SET_ONCE_QUARK.to_glib(),
|
||||
1 as *mut _,
|
||||
);
|
||||
}
|
||||
|
||||
gst_sys::gst_bus_set_sync_handler(
|
||||
self.to_glib_none().0,
|
||||
bus,
|
||||
Some(trampoline_sync::<F>),
|
||||
into_raw_sync(func),
|
||||
Some(destroy_closure_sync::<F>),
|
||||
|
@ -167,7 +189,15 @@ impl Bus {
|
|||
}
|
||||
|
||||
pub fn unset_sync_handler(&self) {
|
||||
// This is not thread-safe before 1.16.3, see
|
||||
// https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/merge_requests/416
|
||||
if ::version() < (1, 16, 3, 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
use std::ptr;
|
||||
|
||||
gst_sys::gst_bus_set_sync_handler(self.to_glib_none().0, None, ptr::null_mut(), None)
|
||||
}
|
||||
}
|
||||
|
@ -217,6 +247,21 @@ impl Bus {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stream(&self) -> BusStream {
|
||||
BusStream::new(self)
|
||||
}
|
||||
|
||||
pub fn stream_filtered<'a>(
|
||||
&self,
|
||||
message_types: &'a [MessageType],
|
||||
) -> impl Stream<Item = Message> + Unpin + Send + 'a {
|
||||
self.stream().filter(move |message| {
|
||||
let message_type = message.get_type();
|
||||
|
||||
future::ready(message_types.contains(&message_type))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -234,49 +279,39 @@ impl<'a> Iterator for Iter<'a> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BusStream(Bus, Arc<Mutex<Option<Waker>>>);
|
||||
pub struct BusStream {
|
||||
bus: Bus,
|
||||
receiver: UnboundedReceiver<Message>,
|
||||
}
|
||||
|
||||
impl BusStream {
|
||||
pub fn new(bus: &Bus) -> Self {
|
||||
skip_assert_initialized!();
|
||||
let waker = Arc::new(Mutex::new(None));
|
||||
let waker_clone = Arc::clone(&waker);
|
||||
|
||||
bus.set_sync_handler(move |_, _| {
|
||||
let mut waker = waker_clone.lock().unwrap();
|
||||
if let Some(waker) = waker.take() {
|
||||
// FIXME: Force type...
|
||||
let waker: Waker = waker;
|
||||
waker.wake();
|
||||
}
|
||||
let bus = bus.clone();
|
||||
let (sender, receiver) = mpsc::unbounded();
|
||||
|
||||
BusSyncReply::Pass
|
||||
bus.set_sync_handler(move |_, message| {
|
||||
let _ = sender.unbounded_send(message.to_owned());
|
||||
|
||||
BusSyncReply::Drop
|
||||
});
|
||||
|
||||
BusStream(bus.clone(), waker)
|
||||
Self { bus, receiver }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BusStream {
|
||||
fn drop(&mut self) {
|
||||
self.0.unset_sync_handler();
|
||||
self.bus.unset_sync_handler();
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for BusStream {
|
||||
type Item = Message;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
let BusStream(ref bus, ref waker) = *self;
|
||||
|
||||
let msg = bus.pop();
|
||||
if let Some(msg) = msg {
|
||||
Poll::Ready(Some(msg))
|
||||
} else {
|
||||
let mut waker = waker.lock().unwrap();
|
||||
*waker = Some(ctx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
fn poll_next(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
|
||||
self.receiver.poll_next_unpin(context)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,4 +341,23 @@ mod tests {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bus_stream() {
|
||||
::init().unwrap();
|
||||
|
||||
let bus = Bus::new();
|
||||
let bus_stream = bus.stream();
|
||||
|
||||
let eos_message = ::Message::new_eos().build();
|
||||
bus.post(&eos_message).unwrap();
|
||||
|
||||
let bus_future = bus_stream.into_future();
|
||||
let (message, _) = futures_executor::block_on(bus_future);
|
||||
|
||||
match message.unwrap().view() {
|
||||
::MessageView::Eos(_) => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
use caps_features::*;
|
||||
use miniobject::*;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use structure::*;
|
||||
|
@ -34,6 +35,21 @@ impl Caps {
|
|||
Builder::new(name)
|
||||
}
|
||||
|
||||
pub fn builder_full() -> BuilderFull<SomeFeatures> {
|
||||
assert_initialized_main_thread!();
|
||||
BuilderFull::new()
|
||||
}
|
||||
|
||||
pub fn builder_full_with_features(features: CapsFeatures) -> BuilderFull<SomeFeatures> {
|
||||
assert_initialized_main_thread!();
|
||||
BuilderFull::new_with_features(features)
|
||||
}
|
||||
|
||||
pub fn builder_full_with_any_features() -> BuilderFull<AnyFeatures> {
|
||||
assert_initialized_main_thread!();
|
||||
BuilderFull::new_with_any_features()
|
||||
}
|
||||
|
||||
pub fn new_empty() -> Self {
|
||||
assert_initialized_main_thread!();
|
||||
unsafe { from_glib_full(gst_sys::gst_caps_new_empty()) }
|
||||
|
@ -56,7 +72,16 @@ impl Caps {
|
|||
|
||||
pub fn fixate(caps: Self) -> Self {
|
||||
skip_assert_initialized!();
|
||||
unsafe { from_glib_full(gst_sys::gst_caps_fixate(caps.into_ptr())) }
|
||||
unsafe {
|
||||
// See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/388
|
||||
assert!(!caps.is_any());
|
||||
let ptr = if caps.is_empty() {
|
||||
gst_sys::gst_caps_new_empty()
|
||||
} else {
|
||||
gst_sys::gst_caps_fixate(caps.into_ptr())
|
||||
};
|
||||
from_glib_full(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn merge(caps: Self, other: Self) -> Self {
|
||||
|
@ -563,6 +588,95 @@ impl<'a> Builder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum AnyFeatures {}
|
||||
pub enum SomeFeatures {}
|
||||
|
||||
pub struct BuilderFull<T> {
|
||||
caps: ::Caps,
|
||||
features: Option<CapsFeatures>,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for BuilderFull<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Builder")
|
||||
.field("caps", &self.caps)
|
||||
.field("features", &self.features)
|
||||
.field("phantom", &self.phantom)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl BuilderFull<SomeFeatures> {
|
||||
fn new() -> Self {
|
||||
BuilderFull {
|
||||
caps: Caps::new_empty(),
|
||||
features: None,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_with_features(features: CapsFeatures) -> Self {
|
||||
BuilderFull {
|
||||
caps: Caps::new_empty(),
|
||||
features: Some(features),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn structure_with_features(self, structure: Structure, features: CapsFeatures) -> Self {
|
||||
self.append_structure(structure, Some(features))
|
||||
}
|
||||
|
||||
pub fn structure_with_any_features(self, structure: Structure) -> Self {
|
||||
self.append_structure(structure, Some(CapsFeatures::new_any()))
|
||||
}
|
||||
}
|
||||
|
||||
impl BuilderFull<AnyFeatures> {
|
||||
fn new_with_any_features() -> Self {
|
||||
BuilderFull {
|
||||
caps: Caps::new_empty(),
|
||||
features: Some(CapsFeatures::new_any()),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BuilderFull<T> {
|
||||
fn append_structure(mut self, structure: Structure, features: Option<CapsFeatures>) -> Self {
|
||||
let features = {
|
||||
match self.features {
|
||||
None => features,
|
||||
Some(ref result) => {
|
||||
let mut result = result.clone();
|
||||
match features {
|
||||
None => Some(result),
|
||||
Some(features) => {
|
||||
features.iter().for_each(|feat| result.add(feat));
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.caps
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
.append_structure_full(structure, features);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn structure(self, structure: Structure) -> Self {
|
||||
self.append_structure(structure, None)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Caps {
|
||||
self.caps
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -656,4 +770,73 @@ mod tests {
|
|||
let caps = Caps::new_simple("foo/bar", &[]);
|
||||
format!("{}", caps);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builder_full() {
|
||||
::init().unwrap();
|
||||
|
||||
let caps = Caps::builder_full()
|
||||
.structure(Structure::builder("audio/x-raw").build())
|
||||
.structure(Structure::builder("video/x-raw").build())
|
||||
.build();
|
||||
assert_eq!(caps.to_string(), "audio/x-raw; video/x-raw");
|
||||
|
||||
let caps = Caps::builder_full()
|
||||
.structure(
|
||||
Structure::builder("audio/x-raw")
|
||||
.field("format", &"S16LE")
|
||||
.build(),
|
||||
)
|
||||
.structure(Structure::builder("video/x-raw").build())
|
||||
.build();
|
||||
assert_eq!(
|
||||
caps.to_string(),
|
||||
"audio/x-raw, format=(string)S16LE; video/x-raw"
|
||||
);
|
||||
|
||||
let caps = Caps::builder_full()
|
||||
.structure_with_any_features(Structure::builder("audio/x-raw").build())
|
||||
.structure_with_features(
|
||||
Structure::builder("video/x-raw").build(),
|
||||
CapsFeatures::new(&["foo:bla", "foo:baz"]),
|
||||
)
|
||||
.build();
|
||||
assert_eq!(
|
||||
caps.to_string(),
|
||||
"audio/x-raw(ANY); video/x-raw(foo:bla, foo:baz)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builder_full_with_features() {
|
||||
::init().unwrap();
|
||||
|
||||
let caps = Caps::builder_full_with_features(CapsFeatures::new(&["foo:bla"]))
|
||||
.structure(Structure::builder("audio/x-raw").build())
|
||||
.structure_with_features(
|
||||
Structure::builder("video/x-raw").build(),
|
||||
CapsFeatures::new(&["foo:baz"]),
|
||||
)
|
||||
.build();
|
||||
assert_eq!(
|
||||
caps.to_string(),
|
||||
"audio/x-raw(foo:bla); video/x-raw(foo:bla, foo:baz)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builder_full_with_any_features() {
|
||||
::init().unwrap();
|
||||
|
||||
let caps = Caps::builder_full_with_any_features()
|
||||
.structure(Structure::builder("audio/x-raw").build())
|
||||
.structure(Structure::builder("video/x-raw").build())
|
||||
.build();
|
||||
assert_eq!(caps.to_string(), "audio/x-raw(ANY); video/x-raw(ANY)");
|
||||
|
||||
let caps = Caps::builder_full_with_any_features()
|
||||
.structure(Structure::builder("audio/x-raw").build())
|
||||
.build();
|
||||
assert_eq!(caps.to_string(), "audio/x-raw(ANY)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ mod tests {
|
|||
let mut pretty_config = ron::ser::PrettyConfig::default();
|
||||
pretty_config.new_line = "".to_string();
|
||||
|
||||
let res = ron::ser::to_string_pretty(&caps, pretty_config.clone());
|
||||
let res = ron::ser::to_string_pretty(&caps, pretty_config);
|
||||
assert_eq!(
|
||||
Ok(concat!(
|
||||
"Some([",
|
||||
|
@ -279,7 +279,7 @@ mod tests {
|
|||
let mut pretty_config = ron::ser::PrettyConfig::default();
|
||||
pretty_config.new_line = "".to_string();
|
||||
|
||||
let res = ron::ser::to_string_pretty(&caps, pretty_config.clone());
|
||||
let res = ron::ser::to_string_pretty(&caps, pretty_config);
|
||||
assert_eq!(
|
||||
Ok(concat!(
|
||||
"Some([",
|
||||
|
@ -339,7 +339,7 @@ mod tests {
|
|||
assert_eq!(Ok("Any".to_owned()), res);
|
||||
|
||||
let caps_empty = Caps::new_empty();
|
||||
let res = ron::ser::to_string_pretty(&caps_empty, pretty_config.clone());
|
||||
let res = ron::ser::to_string_pretty(&caps_empty, pretty_config);
|
||||
assert_eq!(Ok("Empty".to_owned()), res);
|
||||
}
|
||||
|
||||
|
|
|
@ -106,13 +106,7 @@ impl ClockId {
|
|||
unsafe {
|
||||
let res =
|
||||
gst_sys::gst_clock_id_compare_func(self.to_glib_none().0, other.to_glib_none().0);
|
||||
if res < 0 {
|
||||
cmp::Ordering::Less
|
||||
} else if res > 0 {
|
||||
cmp::Ordering::Greater
|
||||
} else {
|
||||
cmp::Ordering::Equal
|
||||
}
|
||||
res.cmp(&0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,13 +87,7 @@ impl cmp::PartialOrd for DateTime {
|
|||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
#[inline]
|
||||
fn get_cmp(delta: i32) -> Option<cmp::Ordering> {
|
||||
Some(if delta < 0 {
|
||||
cmp::Ordering::Less
|
||||
} else if delta == 0 {
|
||||
cmp::Ordering::Equal
|
||||
} else {
|
||||
cmp::Ordering::Greater
|
||||
})
|
||||
Some(delta.cmp(&0))
|
||||
}
|
||||
|
||||
if !(self.has_year() && other.has_year()) {
|
||||
|
@ -239,6 +233,7 @@ impl fmt::Display for DateTime {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
#[test]
|
||||
fn test_to_utc() {
|
||||
::init().unwrap();
|
||||
|
|
|
@ -197,7 +197,7 @@ mod tests {
|
|||
assert_eq!(Ok("YM(2018, 5)".to_owned()), res);
|
||||
|
||||
let datetime = DateTime::new_y(2018);
|
||||
let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone());
|
||||
let res = ron::ser::to_string_pretty(&datetime, pretty_config);
|
||||
assert_eq!(Ok("Y(2018)".to_owned()), res);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,13 @@ use StateChangeReturn;
|
|||
use StateChangeSuccess;
|
||||
|
||||
use std::ffi::CStr;
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
use std::future::Future;
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
use std::marker::Unpin;
|
||||
use std::mem;
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
use std::pin::Pin;
|
||||
|
||||
use libc;
|
||||
|
||||
|
@ -247,6 +253,15 @@ pub trait ElementExtManual: 'static {
|
|||
fn call_async<F>(&self, func: F)
|
||||
where
|
||||
F: FnOnce(&Self) + Send + 'static;
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
fn call_async_future<F, T>(
|
||||
&self,
|
||||
func: F,
|
||||
) -> Pin<Box<dyn Future<Output = T> + Unpin + Send + 'static>>
|
||||
where
|
||||
F: FnOnce(&Self) -> T + Send + 'static,
|
||||
T: Send + 'static;
|
||||
}
|
||||
|
||||
impl<O: IsA<Element>> ElementExtManual for O {
|
||||
|
@ -487,7 +502,7 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
fn get_pads(&self) -> Vec<Pad> {
|
||||
unsafe {
|
||||
let elt: &gst_sys::GstElement = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&elt.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&elt.object.lock);
|
||||
FromGlibPtrContainer::from_glib_none(elt.pads)
|
||||
}
|
||||
}
|
||||
|
@ -495,7 +510,7 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
fn get_sink_pads(&self) -> Vec<Pad> {
|
||||
unsafe {
|
||||
let elt: &gst_sys::GstElement = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&elt.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&elt.object.lock);
|
||||
FromGlibPtrContainer::from_glib_none(elt.sinkpads)
|
||||
}
|
||||
}
|
||||
|
@ -503,7 +518,7 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
fn get_src_pads(&self) -> Vec<Pad> {
|
||||
unsafe {
|
||||
let elt: &gst_sys::GstElement = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&elt.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&elt.object.lock);
|
||||
FromGlibPtrContainer::from_glib_none(elt.srcpads)
|
||||
}
|
||||
}
|
||||
|
@ -511,7 +526,7 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
fn num_pads(&self) -> u16 {
|
||||
unsafe {
|
||||
let elt: &gst_sys::GstElement = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&elt.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&elt.object.lock);
|
||||
elt.numpads
|
||||
}
|
||||
}
|
||||
|
@ -519,7 +534,7 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
fn num_sink_pads(&self) -> u16 {
|
||||
unsafe {
|
||||
let elt: &gst_sys::GstElement = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&elt.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&elt.object.lock);
|
||||
elt.numsinkpads
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +542,7 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
fn num_src_pads(&self) -> u16 {
|
||||
unsafe {
|
||||
let elt: &gst_sys::GstElement = &*(self.as_ptr() as *const _);
|
||||
::utils::MutexGuard::lock(&elt.object.lock);
|
||||
let _guard = ::utils::MutexGuard::lock(&elt.object.lock);
|
||||
elt.numsrcpads
|
||||
}
|
||||
}
|
||||
|
@ -768,6 +783,27 @@ impl<O: IsA<Element>> ElementExtManual for O {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
fn call_async_future<F, T>(
|
||||
&self,
|
||||
func: F,
|
||||
) -> Pin<Box<dyn Future<Output = T> + Unpin + Send + 'static>>
|
||||
where
|
||||
F: FnOnce(&Self) -> T + Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
use futures_channel::oneshot;
|
||||
use futures_util::future::FutureExt;
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
|
||||
self.call_async(move |element| {
|
||||
let _ = sender.send(func(element));
|
||||
});
|
||||
|
||||
Box::pin(receiver.map(|res| res.expect("sender dropped")))
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementClass {
|
||||
|
|
|
@ -145,7 +145,7 @@ impl LoggableError {
|
|||
|
||||
pub fn log(&self) {
|
||||
self.category.log(
|
||||
None as Option<&::Object>,
|
||||
None as Option<&glib::Object>,
|
||||
::DebugLevel::Error,
|
||||
self.bool_error.filename,
|
||||
self.bool_error.function,
|
||||
|
@ -154,7 +154,7 @@ impl LoggableError {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn log_with_object<O: IsA<::Object>>(&self, obj: &O) {
|
||||
pub fn log_with_object<O: IsA<glib::Object>>(&self, obj: &O) {
|
||||
self.category.log(
|
||||
Some(obj),
|
||||
::DebugLevel::Error,
|
||||
|
|
|
@ -68,13 +68,7 @@ impl cmp::Ord for Seqnum {
|
|||
fn cmp(&self, other: &Seqnum) -> cmp::Ordering {
|
||||
unsafe {
|
||||
let ret = gst_sys::gst_util_seqnum_compare(self.0, other.0);
|
||||
if ret < 0 {
|
||||
cmp::Ordering::Less
|
||||
} else if ret > 0 {
|
||||
cmp::Ordering::Greater
|
||||
} else {
|
||||
cmp::Ordering::Equal
|
||||
}
|
||||
ret.cmp(&0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1451,11 +1445,8 @@ impl<'a> NavigationBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_navigation(structure.to_glib_none().0);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_navigation(structure.into_ptr())
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1569,14 +1560,8 @@ impl<'a> CustomUpstreamBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_custom(
|
||||
gst_sys::GST_EVENT_CUSTOM_UPSTREAM,
|
||||
structure.to_glib_none().0,
|
||||
);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_custom(gst_sys::GST_EVENT_CUSTOM_UPSTREAM, structure.into_ptr())
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1594,14 +1579,8 @@ impl<'a> CustomDownstreamBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_custom(
|
||||
gst_sys::GST_EVENT_CUSTOM_DOWNSTREAM,
|
||||
structure.to_glib_none().0,
|
||||
);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_custom(gst_sys::GST_EVENT_CUSTOM_DOWNSTREAM, structure.into_ptr())
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1619,14 +1598,11 @@ impl<'a> CustomDownstreamOobBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_custom(
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_custom(
|
||||
gst_sys::GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
|
||||
structure.to_glib_none().0,
|
||||
);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
structure.into_ptr(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1644,14 +1620,11 @@ impl<'a> CustomDownstreamStickyBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_custom(
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_custom(
|
||||
gst_sys::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY,
|
||||
structure.to_glib_none().0,
|
||||
);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
structure.into_ptr(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1669,14 +1642,8 @@ impl<'a> CustomBothBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_custom(
|
||||
gst_sys::GST_EVENT_CUSTOM_BOTH,
|
||||
structure.to_glib_none().0,
|
||||
);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_custom(gst_sys::GST_EVENT_CUSTOM_BOTH, structure.into_ptr())
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1694,14 +1661,8 @@ impl<'a> CustomBothOobBuilder<'a> {
|
|||
}
|
||||
|
||||
event_builder_generic_impl!(|s: &mut Self| {
|
||||
let structure = s.structure.take();
|
||||
let ev = gst_sys::gst_event_new_custom(
|
||||
gst_sys::GST_EVENT_CUSTOM_BOTH_OOB,
|
||||
structure.to_glib_none().0,
|
||||
);
|
||||
mem::forget(structure);
|
||||
|
||||
ev
|
||||
let structure = s.structure.take().unwrap();
|
||||
gst_sys::gst_event_new_custom(gst_sys::GST_EVENT_CUSTOM_BOTH_OOB, structure.into_ptr())
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue