Allow custom pipelines, autodetect live sources

This commit is contained in:
Vladimir Romashchenko 2024-08-05 17:55:50 -04:00
parent 217fa7730a
commit be21d2a19b
No known key found for this signature in database
GPG key ID: E5B7EA4A9E1D48F4
5 changed files with 93 additions and 79 deletions

105
Cargo.lock generated
View file

@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289"
dependencies = [
"android-properties",
"bitflags 2.4.2",
"bitflags 2.6.0",
"cc",
"cesu8",
"jni",
@ -162,9 +162,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "block"
@ -214,7 +214,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -235,7 +235,7 @@ version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"log",
"polling",
"rustix",
@ -542,7 +542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
dependencies = [
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -557,7 +557,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"libloading 0.8.1",
"winapi",
]
@ -589,7 +589,7 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytemuck",
"drm-ffi",
"drm-fourcc",
@ -781,7 +781,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -856,7 +856,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -956,7 +956,7 @@ version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab9e86540b5d8402e905ad4ce7d6aa544092131ab564f3102175af176b90a053"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"futures-channel",
"futures-core",
"futures-executor",
@ -982,7 +982,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -1045,7 +1045,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"gpu-alloc-types",
]
@ -1055,7 +1055,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
]
[[package]]
@ -1077,7 +1077,7 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"gpu-descriptor-types",
"hashbrown",
]
@ -1088,7 +1088,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
]
[[package]]
@ -1219,7 +1219,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"com",
"libc",
"libloading 0.8.1",
@ -1278,7 +1278,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55f9226618af7e8155fc8a233e4d84dc1ec44438705f972e35d5d50e62f937df"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"glam",
"log",
"num-traits",
@ -1321,7 +1321,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0660df444c64a13f72999c55a324f6d3ea020167bb1af8ef43fe2bff168d8c27"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytemuck",
"cosmic-text",
"half",
@ -1424,6 +1424,7 @@ dependencies = [
"glib",
"gstreamer",
"gstreamer-app",
"gstreamer-base",
"iced",
"iced_native",
"iced_wgpu",
@ -1437,7 +1438,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa5d3ce370c7044ddc9535c8f87057f1008434a495be6b9f46b2666c3e9638f7"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytemuck",
"futures",
"glam",
@ -1677,7 +1678,7 @@ version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"libc",
"redox_syscall 0.4.1",
]
@ -1730,9 +1731,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.1"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memmap2"
@ -1758,7 +1759,7 @@ version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"block",
"core-graphics-types",
"foreign-types",
@ -1796,7 +1797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8878eb410fc90853da3908aebfe61d73d26d4437ef850b70050461f939509899"
dependencies = [
"bit-set",
"bitflags 2.4.2",
"bitflags 2.6.0",
"codespan-reporting",
"hexf-parse",
"indexmap",
@ -1815,7 +1816,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"jni-sys",
"log",
"ndk-sys",
@ -1896,7 +1897,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -2037,7 +2038,7 @@ checksum = "e05d1c929301fee6830dafa764341118829b2535c216b0571e3821ecac5c885b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -2130,7 +2131,7 @@ dependencies = [
"phf_shared",
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -2204,9 +2205,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.78"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
@ -2357,7 +2358,7 @@ version = "0.38.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys 0.4.13",
@ -2438,7 +2439,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -2492,7 +2493,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"calloop",
"calloop-wayland-source",
"cursor-icon",
@ -2577,7 +2578,7 @@ version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
]
[[package]]
@ -2622,9 +2623,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.49"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
@ -2685,7 +2686,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -2825,7 +2826,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]
@ -2988,7 +2989,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
"wasm-bindgen-shared",
]
@ -3022,7 +3023,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3068,7 +3069,7 @@ version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"rustix",
"wayland-backend",
"wayland-scanner",
@ -3080,7 +3081,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"cursor-icon",
"wayland-backend",
]
@ -3102,7 +3103,7 @@ version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-scanner",
@ -3114,7 +3115,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@ -3127,7 +3128,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@ -3216,7 +3217,7 @@ checksum = "6b15e451d4060ada0d99a64df44e4d590213496da7c4f245572d51071e8e30ed"
dependencies = [
"arrayvec",
"bit-vec",
"bitflags 2.4.2",
"bitflags 2.6.0",
"cfg_aliases 0.1.1",
"codespan-reporting",
"indexmap",
@ -3244,7 +3245,7 @@ dependencies = [
"arrayvec",
"ash",
"bit-set",
"bitflags 2.4.2",
"bitflags 2.6.0",
"block",
"cfg_aliases 0.1.1",
"core-graphics-types",
@ -3284,7 +3285,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "895fcbeb772bfb049eb80b2d6e47f6c9af235284e9703c96fc0218a42ffd5af2"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"js-sys",
"web-sys",
]
@ -3566,7 +3567,7 @@ dependencies = [
"ahash",
"android-activity",
"atomic-waker",
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytemuck",
"calloop",
"cfg_aliases 0.1.1",
@ -3667,7 +3668,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"dlib",
"log",
"once_cell",
@ -3721,7 +3722,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
"syn 2.0.72",
]
[[package]]

View file

@ -21,6 +21,7 @@ iced_native = "0.10"
iced_wgpu = "0.12"
gstreamer = "0.22"
gstreamer-app = "0.22" # appsink
gstreamer-base = "0.22" # basesrc
glib = "0.19" # gobject traits and error type
thiserror = "1"
url = "2" # media uri

View file

@ -39,7 +39,6 @@ impl Sandbox for App {
.unwrap(),
)
.unwrap(),
false,
)
.unwrap();
App {

View file

@ -60,6 +60,8 @@ pub enum Error {
Bool(#[from] glib::BoolError),
#[error("failed to get the gstreamer bus")]
Bus,
#[error("failed to get AppSink element with name='{0}' from gstreamer pipeline")]
AppSink(String),
#[error("{0}")]
StateChange(#[from] gst::StateChangeError),
#[error("failed to cast gstreamer element")]

View file

@ -1,7 +1,9 @@
use crate::Error;
use gst::prelude::*;
use gst_base::prelude::*;
use gstreamer as gst;
use gstreamer_app as gst_app;
use gstreamer_base as gst_base;
use iced::widget::image as img;
use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
@ -44,7 +46,7 @@ pub(crate) struct Internal {
pub(crate) id: u64,
pub(crate) bus: gst::Bus,
pub(crate) source: gst::Bin,
pub(crate) source: gst::Pipeline,
pub(crate) width: i32,
pub(crate) height: i32,
@ -110,35 +112,45 @@ impl Drop for Video {
impl Video {
/// Create a new video player from a given video which loads from `uri`.
///
/// If `live` is set then no duration is queried (as this will result in an error and is non-sensical for live streams).
/// Set `live` if the streaming source is indefinite (e.g. a live stream).
/// Note that this will cause the duration to be zero.
pub fn new(uri: &url::Url, live: bool) -> Result<Self, Error> {
/// Note that live sourced will report the duration to be zero.
pub fn new(uri: &url::Url) -> Result<Self, Error> {
let pipeline = format!("uridecodebin uri=\"{}\" ! videoconvert ! videoscale ! appsink name=iced_video caps=video/x-raw,format=RGBA,pixel-aspect-ratio=1/1", uri.as_str());
Self::from_pipeline(pipeline)
}
pub fn from_pipeline<S: AsRef<str>>(pipeline: S) -> Result<Self, Error> {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
gst::init()?;
let source = gst::parse::launch(&format!("playbin uri=\"{}\" video-sink=\"videoconvert ! videoscale ! appsink name=app_sink caps=video/x-raw,format=RGBA,pixel-aspect-ratio=1/1\"", uri.as_str()))?;
let source = source.downcast::<gst::Bin>().unwrap();
let video_sink: gst::Element = source.property("video-sink");
let pad = video_sink.pads().get(0).cloned().unwrap();
let pad = pad.dynamic_cast::<gst::GhostPad>().unwrap();
let bin = pad
.parent_element()
.unwrap()
.downcast::<gst::Bin>()
let pipeline = gst::parse::launch(pipeline.as_ref())?
.downcast::<gst::Pipeline>()
.map_err(|_| Error::Cast)?;
let mut live = false;
pipeline
.iterate_sources()
.foreach(|elem| {
if let Ok(src) = elem.downcast::<gst_base::BaseSrc>() {
if src.is_live() {
live = true;
}
}
})
.unwrap();
let app_sink = bin.by_name("app_sink").unwrap();
let app_sink = app_sink.downcast::<gst_app::AppSink>().unwrap();
let app_sink_name = "iced_video";
let app_sink = pipeline
.by_name(app_sink_name)
.and_then(|elem| elem.downcast::<gst_app::AppSink>().ok())
.ok_or(Error::AppSink(app_sink_name.to_string()))?;
source.set_state(gst::State::Playing)?;
let pad = app_sink.pads().first().cloned().unwrap();
pipeline.set_state(gst::State::Playing)?;
// wait for up to 5 seconds until the decoder gets the source capabilities
source.state(gst::ClockTime::from_seconds(5)).0?;
pipeline.state(gst::ClockTime::from_seconds(5)).0?;
// extract resolution and framerate
// TODO(jazzfool): maybe we want to extract some other information too?
@ -152,7 +164,7 @@ impl Video {
let duration = if !live {
std::time::Duration::from_nanos(
source
pipeline
.query_duration::<gst::ClockTime>()
.ok_or(Error::Duration)?
.nseconds(),
@ -194,8 +206,8 @@ impl Video {
Ok(Video(RefCell::new(Internal {
id,
bus: source.bus().unwrap(),
source,
bus: pipeline.bus().unwrap(),
source: pipeline,
width,
height,
@ -231,14 +243,14 @@ impl Video {
///
/// This uses a linear scale, for example `0.5` is perceived as half as loud.
pub fn set_volume(&mut self, volume: f64) {
self.0.borrow().source.set_property("volume", &volume);
self.0.borrow().source.set_property("volume", volume);
}
/// Set if the audio is muted or not, without changing the volume.
pub fn set_muted(&mut self, muted: bool) {
let mut inner = self.0.borrow_mut();
inner.muted = muted;
inner.source.set_property("mute", &muted);
inner.source.set_property("mute", muted);
}
/// Get if the audio is muted or not.
@ -292,7 +304,6 @@ impl Video {
.query_position::<gst::ClockTime>()
.map_or(0, |pos| pos.nseconds()),
)
.into()
}
/// Get the media duration.