Compare commits
19 commits
4a1bfc975c
...
d13c21206e
| Author | SHA1 | Date | |
|---|---|---|---|
| d13c21206e | |||
| d3e1c26a48 | |||
| 9d84952c81 | |||
| f19ac9d797 | |||
|
|
3217824a5f | ||
|
|
3035ae3565 | ||
|
|
e56a3a4936 | ||
|
|
7591a5dbb6 | ||
| a43ff8463b | |||
| 076c840120 | |||
| 86ae7d1b37 | |||
| b989d63c2e | |||
| 91b1ad874d | |||
| bee543258a | |||
| a1a1c07932 | |||
| a670d2afd7 | |||
| fd03f98738 | |||
| 1e0a8add0f | |||
| 22e5890a7c |
7 changed files with 479 additions and 521 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,4 +10,3 @@
|
||||||
!/vendor/iced_video_player/
|
!/vendor/iced_video_player/
|
||||||
!/vendor/iced_video_player/**
|
!/vendor/iced_video_player/**
|
||||||
/vendor.tar
|
/vendor.tar
|
||||||
.idea/
|
|
||||||
|
|
|
||||||
746
Cargo.lock
generated
746
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "cosmic-player"
|
name = "cosmic-player"
|
||||||
version = "1.2.0"
|
version = "1.0.14"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.93"
|
rust-version = "1.93"
|
||||||
|
|
||||||
|
|
|
||||||
24
debian/changelog
vendored
24
debian/changelog
vendored
|
|
@ -1,27 +1,3 @@
|
||||||
cosmic-player (1.2.0) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.2.0 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 30 Jun 2026 12:21:32 -0600
|
|
||||||
|
|
||||||
cosmic-player (1.1.0) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.1.0 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 23 Jun 2026 08:48:43 -0600
|
|
||||||
|
|
||||||
cosmic-player (1.0.16) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.0.16 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 09 Jun 2026 10:26:19 -0600
|
|
||||||
|
|
||||||
cosmic-player (1.0.15) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.0.15 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 02 Jun 2026 11:02:44 -0600
|
|
||||||
|
|
||||||
cosmic-player (1.0.14) noble; urgency=medium
|
cosmic-player (1.0.14) noble; urgency=medium
|
||||||
|
|
||||||
* Epoch 1.0.14 version update
|
* Epoch 1.0.14 version update
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M6 8C6 6.96533 6.94659 6.18931 7.96116 6.39223L14.0388 7.60776C14.4676 7.69351 14.4676 8.30648 14.0388 8.39223L7.96116 9.60776C6.94659 9.81068 6 9.03467 6 8Z" fill="#232323"/>
|
|
||||||
<path d="M11.9727 4.96582L11.9717 4.96484C11.0579 3.77097 9.61954 3 8 3C5.23858 3 3 5.23858 3 8C3 10.7614 5.23858 13 8 13C9.58934 13 11.0568 12.1775 11.9727 11.0215C12.3575 10.4961 13.0321 10.3355 13.4795 10.6631C13.9268 10.9907 13.9775 11.6826 13.5928 12.208C12.3112 13.8352 10.232 15 8 15C4.13401 15 1 11.866 1 8C1 4.13401 4.13401 1 8 1C10.2173 1 12.3105 2.17054 13.5928 3.7793C13.9775 4.30475 13.9268 4.99657 13.4795 5.32422C13.0321 5.65182 12.3575 5.49119 11.9727 4.96582Z" fill="#232323"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 782 B |
144
src/main.rs
144
src/main.rs
|
|
@ -55,9 +55,6 @@ const JUMP_BACKWARD_ICON: &[u8] =
|
||||||
const JUMP_FORWARD_ICON: &[u8] =
|
const JUMP_FORWARD_ICON: &[u8] =
|
||||||
include_bytes!("../res/icons/hicolor/16x16/apps/jump-forward-10-symbolic.svg");
|
include_bytes!("../res/icons/hicolor/16x16/apps/jump-forward-10-symbolic.svg");
|
||||||
|
|
||||||
const PLAYBACK_SPEED_ICON: &[u8] =
|
|
||||||
include_bytes!("../res/icons/hicolor/16x16/apps/playback-speed-symbolic.svg");
|
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
fn language_name(code: &str) -> Option<String> {
|
fn language_name(code: &str) -> Option<String> {
|
||||||
|
|
@ -232,7 +229,6 @@ pub struct Flags {
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum DropdownKind {
|
pub enum DropdownKind {
|
||||||
Audio,
|
Audio,
|
||||||
Speed,
|
|
||||||
Subtitle,
|
Subtitle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,7 +293,7 @@ pub enum Message {
|
||||||
MultipleLoad(Vec<url::Url>),
|
MultipleLoad(Vec<url::Url>),
|
||||||
Fullscreen,
|
Fullscreen,
|
||||||
LaunchUrl(String),
|
LaunchUrl(String),
|
||||||
Key(Modifiers, Physical, Key),
|
Key(Modifiers, Key),
|
||||||
AudioCode(usize),
|
AudioCode(usize),
|
||||||
AudioToggle,
|
AudioToggle,
|
||||||
AudioVolume(f64),
|
AudioVolume(f64),
|
||||||
|
|
@ -320,8 +316,6 @@ pub enum Message {
|
||||||
NewFrame,
|
NewFrame,
|
||||||
Reload,
|
Reload,
|
||||||
AbRepeat,
|
AbRepeat,
|
||||||
VideoAreaClick,
|
|
||||||
PlaybackSpeed(f64),
|
|
||||||
ShowControls,
|
ShowControls,
|
||||||
SystemThemeModeChange(cosmic_theme::ThemeMode),
|
SystemThemeModeChange(cosmic_theme::ThemeMode),
|
||||||
ToggleAbout,
|
ToggleAbout,
|
||||||
|
|
@ -354,7 +348,6 @@ pub struct App {
|
||||||
text_codes: Vec<TextCode>,
|
text_codes: Vec<TextCode>,
|
||||||
current_text: Option<i32>,
|
current_text: Option<i32>,
|
||||||
ab_repeat: Option<(Option<f64>, Option<f64>)>,
|
ab_repeat: Option<(Option<f64>, Option<f64>)>,
|
||||||
playback_speed: f64,
|
|
||||||
#[cfg(feature = "xdg-portal")]
|
#[cfg(feature = "xdg-portal")]
|
||||||
inhibit: tokio::sync::watch::Sender<bool>,
|
inhibit: tokio::sync::watch::Sender<bool>,
|
||||||
}
|
}
|
||||||
|
|
@ -469,11 +462,6 @@ impl App {
|
||||||
self.set_looping_from_repeat_state();
|
self.set_looping_from_repeat_state();
|
||||||
self.update_flags();
|
self.update_flags();
|
||||||
self.update_mpris_meta();
|
self.update_mpris_meta();
|
||||||
if self.playback_speed != 1.0 {
|
|
||||||
if let Some(video) = &mut self.video_opt {
|
|
||||||
Self::apply_speed(video, self.playback_speed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.update_title()
|
self.update_title()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -866,12 +854,6 @@ impl App {
|
||||||
video.set_looping(self.flags.config_state.player_state.repeat == RepeatState::Track);
|
video.set_looping(self.flags.config_state.player_state.repeat == RepeatState::Track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_speed(video: &mut Video, speed: f64) {
|
|
||||||
if let Err(err) = video.set_speed(speed) {
|
|
||||||
log::warn!("failed to set playback speed {}: {}", speed, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement [`cosmic::Application`] to integrate with COSMIC.
|
/// Implement [`cosmic::Application`] to integrate with COSMIC.
|
||||||
|
|
@ -949,7 +931,6 @@ impl Application for App {
|
||||||
text_codes: Vec::new(),
|
text_codes: Vec::new(),
|
||||||
current_text: None,
|
current_text: None,
|
||||||
ab_repeat: None,
|
ab_repeat: None,
|
||||||
playback_speed: 1.0,
|
|
||||||
#[cfg(feature = "xdg-portal")]
|
#[cfg(feature = "xdg-portal")]
|
||||||
inhibit,
|
inhibit,
|
||||||
};
|
};
|
||||||
|
|
@ -1251,9 +1232,9 @@ impl Application for App {
|
||||||
log::warn!("failed to open URL {:?}: {}", url, err);
|
log::warn!("failed to open URL {:?}: {}", url, err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::Key(modifiers, physical, key) => {
|
Message::Key(modifiers, key) => {
|
||||||
for (key_bind, action) in self.key_binds.iter() {
|
for (key_bind, action) in self.key_binds.iter() {
|
||||||
if key_bind.matches(modifiers, &key, Some(&physical)) {
|
if key_bind.matches(modifiers, &key, None) {
|
||||||
return self.update(action.message());
|
return self.update(action.message());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1385,10 +1366,10 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Message::SeekRelative(secs) => {
|
Message::SeekRelative(secs) => {
|
||||||
if let Some(video) = &mut self.video_opt {
|
if let Some(video) = &mut self.video_opt {
|
||||||
self.position =
|
self.position = video.position().as_secs_f64();
|
||||||
(video.position().as_secs_f64() + secs).clamp(0.0, self.duration);
|
let duration =
|
||||||
let target = Duration::try_from_secs_f64(self.position).unwrap_or_default();
|
Duration::try_from_secs_f64(self.position + secs).unwrap_or_default();
|
||||||
video.seek(target, true).expect("seek");
|
video.seek(duration, true).expect("seek");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SeekRelease => {
|
Message::SeekRelease => {
|
||||||
|
|
@ -1510,19 +1491,13 @@ impl Application for App {
|
||||||
if let Some(video) = &mut self.video_opt
|
if let Some(video) = &mut self.video_opt
|
||||||
&& video.has_video()
|
&& video.has_video()
|
||||||
{
|
{
|
||||||
video.set_paused(true);
|
|
||||||
video.pipeline().send_event(gst::event::Step::new(
|
video.pipeline().send_event(gst::event::Step::new(
|
||||||
gst::format::Buffers::from_u64(1),
|
gst::format::Buffers::from_u64(1),
|
||||||
1.0,
|
1.0,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
));
|
));
|
||||||
|
video.set_paused(true);
|
||||||
let fps = get_framerate(video).unwrap_or(30.0);
|
|
||||||
let frame_duration = Duration::from_secs_f64(1.0 / fps);
|
|
||||||
|
|
||||||
self.position = (video.position().as_secs_f64() + frame_duration.as_secs_f64())
|
|
||||||
.clamp(0.0, self.duration);
|
|
||||||
self.update_controls(true);
|
self.update_controls(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1531,33 +1506,16 @@ impl Application for App {
|
||||||
&& video.has_video()
|
&& video.has_video()
|
||||||
{
|
{
|
||||||
// TODO: Improve Accuracy.
|
// TODO: Improve Accuracy.
|
||||||
video.set_paused(true);
|
|
||||||
|
|
||||||
let current = video.position();
|
let current = video.position();
|
||||||
let fps = get_framerate(video).unwrap_or(30.0);
|
let fps = get_framerate(video).unwrap_or(30.0);
|
||||||
let frame_duration = Duration::from_secs_f64(1.0 / fps);
|
let frame_duration = Duration::from_secs_f64(1.0 / fps);
|
||||||
let target = current.saturating_sub(frame_duration + Duration::from_millis(1));
|
let target = current.saturating_sub(frame_duration + Duration::from_millis(1));
|
||||||
|
|
||||||
self.position = target.as_secs_f64().clamp(0.0, self.duration);
|
|
||||||
video.seek(target, true).expect("seek");
|
video.seek(target, true).expect("seek");
|
||||||
|
video.set_paused(true);
|
||||||
self.update_controls(true);
|
self.update_controls(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::PlaybackSpeed(speed) => {
|
|
||||||
self.playback_speed = speed;
|
|
||||||
self.dropdown_opt = None;
|
|
||||||
if let Some(video) = &mut self.video_opt {
|
|
||||||
Self::apply_speed(video, speed);
|
|
||||||
}
|
|
||||||
self.update_controls(true);
|
|
||||||
}
|
|
||||||
Message::VideoAreaClick => {
|
|
||||||
if self.dropdown_opt.is_some() {
|
|
||||||
self.dropdown_opt = None;
|
|
||||||
} else {
|
|
||||||
return self.update(Message::PlayPause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message::AbRepeat => {
|
Message::AbRepeat => {
|
||||||
let current_opt = self.video_opt.as_ref().map(|v| v.position().as_secs_f64());
|
let current_opt = self.video_opt.as_ref().map(|v| v.position().as_secs_f64());
|
||||||
if let Some(current) = current_opt {
|
if let Some(current) = current_opt {
|
||||||
|
|
@ -1835,7 +1793,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mouse_area = widget::mouse_area(video_player)
|
let mouse_area = widget::mouse_area(video_player)
|
||||||
.on_press(Message::VideoAreaClick)
|
.on_press(Message::PlayPause)
|
||||||
.on_double_press(Message::Fullscreen);
|
.on_double_press(Message::Fullscreen);
|
||||||
|
|
||||||
let mut popover = widget::popover(mouse_area).position(widget::popover::Position::Bottom);
|
let mut popover = widget::popover(mouse_area).position(widget::popover::Position::Bottom);
|
||||||
|
|
@ -1872,58 +1830,6 @@ impl Application for App {
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DropdownKind::Speed => {
|
|
||||||
for &speed in &[0.75f64, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25] {
|
|
||||||
let s = format!("{:.2}", speed);
|
|
||||||
let speed_str =
|
|
||||||
format!("{}x", s.trim_end_matches('0').trim_end_matches('.'));
|
|
||||||
let is_active = (self.playback_speed - speed).abs() < 0.01;
|
|
||||||
|
|
||||||
let icon: Element<_> = if is_active {
|
|
||||||
widget::icon::from_name("object-select-symbolic")
|
|
||||||
.size(16)
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
widget::container(widget::space::horizontal())
|
|
||||||
.width(Length::Fixed(16.0))
|
|
||||||
.into()
|
|
||||||
};
|
|
||||||
|
|
||||||
let label: Element<_> = if is_active {
|
|
||||||
widget::text(speed_str).font(font::bold()).into()
|
|
||||||
} else {
|
|
||||||
widget::text(speed_str).into()
|
|
||||||
};
|
|
||||||
|
|
||||||
let row_content = widget::row::with_children(vec![icon, label])
|
|
||||||
.spacing(space_xs)
|
|
||||||
.align_y(Alignment::Center);
|
|
||||||
|
|
||||||
let content: Element<_> = if is_active {
|
|
||||||
widget::container(row_content)
|
|
||||||
.class(theme::Container::custom(|theme| {
|
|
||||||
let accent: Color = theme.cosmic().accent_color().into();
|
|
||||||
widget::container::Style {
|
|
||||||
icon_color: Some(accent),
|
|
||||||
text_color: Some(accent),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
row_content.into()
|
|
||||||
};
|
|
||||||
|
|
||||||
items.push(
|
|
||||||
widget::button::custom(content)
|
|
||||||
.width(Length::Fill)
|
|
||||||
.padding([12.0f32, 8.0f32])
|
|
||||||
.class(theme::Button::MenuItem)
|
|
||||||
.on_press(Message::PlaybackSpeed(speed))
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DropdownKind::Subtitle => {
|
DropdownKind::Subtitle => {
|
||||||
if !self.audio_codes.is_empty() {
|
if !self.audio_codes.is_empty() {
|
||||||
items.push(widget::text::heading(fl!("audio")).into());
|
items.push(widget::text::heading(fl!("audio")).into());
|
||||||
|
|
@ -1952,20 +1858,14 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let use_padding = !matches!(dropdown, DropdownKind::Speed);
|
|
||||||
let mut column = widget::column::with_capacity(items.len());
|
let mut column = widget::column::with_capacity(items.len());
|
||||||
for item in items {
|
for item in items {
|
||||||
column = column.push(if use_padding {
|
column = column.push(widget::container(item).padding([space_xxs, space_m]));
|
||||||
widget::container(item).padding([space_xxs, space_m]).into()
|
|
||||||
} else {
|
|
||||||
item
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
popup_items.push(
|
popup_items.push(
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![
|
||||||
widget::space::horizontal().into(),
|
widget::space::horizontal().into(),
|
||||||
widget::mouse_area(
|
|
||||||
widget::container(column)
|
widget::container(column)
|
||||||
.padding(1)
|
.padding(1)
|
||||||
//TODO: move style to libcosmic
|
//TODO: move style to libcosmic
|
||||||
|
|
@ -1984,9 +1884,7 @@ impl Application for App {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.width(Length::Fixed(240.0)),
|
.width(Length::Fixed(240.0))
|
||||||
)
|
|
||||||
.on_press(Message::ShowControls)
|
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -2083,12 +1981,6 @@ impl Application for App {
|
||||||
)
|
)
|
||||||
.on_press(Message::DropdownToggle(DropdownKind::Subtitle)),
|
.on_press(Message::DropdownToggle(DropdownKind::Subtitle)),
|
||||||
)
|
)
|
||||||
.push(
|
|
||||||
widget::button::icon(
|
|
||||||
widget::icon::from_svg_bytes(PLAYBACK_SPEED_ICON).symbolic(true),
|
|
||||||
)
|
|
||||||
.on_press(Message::DropdownToggle(DropdownKind::Speed)),
|
|
||||||
)
|
|
||||||
.push(
|
.push(
|
||||||
widget::button::icon(
|
widget::button::icon(
|
||||||
widget::icon::from_name("view-fullscreen-symbolic").size(16),
|
widget::icon::from_name("view-fullscreen-symbolic").size(16),
|
||||||
|
|
@ -2116,18 +2008,14 @@ impl Application for App {
|
||||||
.on_press(Message::DropdownToggle(DropdownKind::Audio)),
|
.on_press(Message::DropdownToggle(DropdownKind::Audio)),
|
||||||
);
|
);
|
||||||
popup_items.push(
|
popup_items.push(
|
||||||
widget::mouse_area(
|
|
||||||
widget::container(row)
|
widget::container(row)
|
||||||
.padding([space_xxs, space_xs])
|
.padding([space_xxs, space_xs])
|
||||||
.class(theme::Container::WindowBackground),
|
.class(theme::Container::WindowBackground)
|
||||||
)
|
|
||||||
.on_press(Message::ShowControls)
|
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.core.is_condensed() {
|
if self.core.is_condensed() {
|
||||||
popup_items.push(
|
popup_items.push(
|
||||||
widget::mouse_area(
|
|
||||||
widget::container(
|
widget::container(
|
||||||
widget::row::with_capacity(3)
|
widget::row::with_capacity(3)
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
|
|
@ -2144,9 +2032,7 @@ impl Application for App {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.padding([space_xxs, space_xs])
|
.padding([space_xxs, space_xs])
|
||||||
.class(theme::Container::WindowBackground),
|
.class(theme::Container::WindowBackground)
|
||||||
)
|
|
||||||
.on_press(Message::ShowControls)
|
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -2181,7 +2067,7 @@ impl Application for App {
|
||||||
physical_key,
|
physical_key,
|
||||||
key,
|
key,
|
||||||
..
|
..
|
||||||
}) => Some(Message::Key(modifiers, physical_key, key)),
|
}) => Some(Message::Key(modifiers, key)),
|
||||||
Event::Mouse(MouseEvent::CursorMoved { .. }) => Some(Message::ShowControls),
|
Event::Mouse(MouseEvent::CursorMoved { .. }) => Some(Message::ShowControls),
|
||||||
Event::Mouse(MouseEvent::WheelScrolled { delta }) => Some(Message::Scrolled(delta)),
|
Event::Mouse(MouseEvent::WheelScrolled { delta }) => Some(Message::Scrolled(delta)),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,6 @@ pub fn new_video(
|
||||||
.downcast::<gst::Pipeline>()
|
.downcast::<gst::Pipeline>()
|
||||||
.map_err(|_| iced_video_player::Error::Cast)
|
.map_err(|_| iced_video_player::Error::Cast)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if let Ok(scaletempo) = gst::ElementFactory::make("scaletempo").build() {
|
|
||||||
pipeline.set_property("audio-filter", &scaletempo);
|
|
||||||
} else {
|
|
||||||
log::warn!("scaletempo element not available; speed changes will affect pitch");
|
|
||||||
}
|
|
||||||
pipeline.connect("element-setup", false, |vals| {
|
pipeline.connect("element-setup", false, |vals| {
|
||||||
let Ok(elem) = vals[1].get::<gst::Element>() else {
|
let Ok(elem) = vals[1].get::<gst::Element>() else {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue