mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-06-20 23:20:36 +00:00
Compare commits
13 commits
main
...
gstreamer-
Author | SHA1 | Date | |
---|---|---|---|
|
2f2aac55a3 | ||
|
31dfcd0a78 | ||
|
b3e233f0c5 | ||
|
58a065caf3 | ||
|
606352d7cf | ||
|
aa2d056ea1 | ||
|
3f9d5cf2f0 | ||
|
149eff08b7 | ||
|
c4e3fff2a2 | ||
|
16e001e3f2 | ||
|
af694e8bc1 | ||
|
66f2969eb9 | ||
|
50efdf6a64 |
|
@ -6,7 +6,7 @@ include:
|
||||||
file: '/templates/debian.yml'
|
file: '/templates/debian.yml'
|
||||||
|
|
||||||
- project: 'gstreamer/gstreamer-rs'
|
- project: 'gstreamer/gstreamer-rs'
|
||||||
ref: main
|
ref: '0.22'
|
||||||
file: '/ci/images_template.yml'
|
file: '/ci/images_template.yml'
|
||||||
|
|
||||||
- project: 'gstreamer/gstreamer'
|
- project: 'gstreamer/gstreamer'
|
||||||
|
|
|
@ -5,6 +5,12 @@ 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),
|
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).
|
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||||
|
|
||||||
|
## [0.12.1] - 2024-02-13
|
||||||
|
### Added
|
||||||
|
- gtk4: Create a window for testing purposes when running in `gst-launch-1.0`
|
||||||
|
or if `GST_GTK4_WINDOW=1` is set.
|
||||||
|
- webrtcsink: Add `msid` property.
|
||||||
|
|
||||||
## [0.12.0] - 2024-02-08
|
## [0.12.0] - 2024-02-08
|
||||||
### Changed
|
### Changed
|
||||||
- ndi: `ndisrc` passes received data downstream without an additional copy, if
|
- ndi: `ndisrc` passes received data downstream without an additional copy, if
|
||||||
|
@ -344,7 +350,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
||||||
- webrtcsink: Make the `turn-server` property a `turn-servers` list
|
- webrtcsink: Make the `turn-server` property a `turn-servers` list
|
||||||
- webrtcsink: Move from async-std to tokio
|
- webrtcsink: Move from async-std to tokio
|
||||||
|
|
||||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.12.0...HEAD
|
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.12.1...HEAD
|
||||||
|
[0.12.1]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.12.0...0.12.1
|
||||||
[0.12.0]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.11.3...0.12.0
|
[0.12.0]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.11.3...0.12.0
|
||||||
[0.11.3]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.11.2...0.11.3
|
[0.11.3]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.11.2...0.11.3
|
||||||
[0.11.2]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.11.1...0.11.2
|
[0.11.2]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.11.1...0.11.2
|
||||||
|
|
532
Cargo.lock
generated
532
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
54
Cargo.toml
54
Cargo.toml
|
@ -113,36 +113,36 @@ panic = 'unwind'
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.12.0-alpha.1"
|
version = "0.12.1"
|
||||||
repository = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs"
|
repository = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.70"
|
rust-version = "1.70"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
|
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.19", version = "0.19" }
|
||||||
gio = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
|
gio = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.19", version = "0.19" }
|
||||||
cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master", features=["use_glib"] }
|
cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.19", version = "0.19", features=["use_glib"] }
|
||||||
pango = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
|
pango = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.19", version = "0.19" }
|
||||||
pangocairo = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
|
pangocairo = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.19", version = "0.19" }
|
||||||
gtk = { package = "gtk4", git = "https://github.com/gtk-rs/gtk4-rs", branch = "master"}
|
gtk = { package = "gtk4", git = "https://github.com/gtk-rs/gtk4-rs", branch = "0.8", version = "0.8"}
|
||||||
gdk-wayland = { package = "gdk4-wayland", git = "https://github.com/gtk-rs/gtk4-rs", branch = "master"}
|
gdk-wayland = { package = "gdk4-wayland", git = "https://github.com/gtk-rs/gtk4-rs", branch = "0.8", version = "0.8"}
|
||||||
gdk-x11 = { package = "gdk4-x11", git = "https://github.com/gtk-rs/gtk4-rs", branch = "master"}
|
gdk-x11 = { package = "gdk4-x11", git = "https://github.com/gtk-rs/gtk4-rs", branch = "0.8", version = "0.8"}
|
||||||
gdk-win32 = { package = "gdk4-win32", git = "https://github.com/gtk-rs/gtk4-rs", branch = "master"}
|
gdk-win32 = { package = "gdk4-win32", git = "https://github.com/gtk-rs/gtk4-rs", branch = "0.8", version = "0.8"}
|
||||||
gst = { package = "gstreamer", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst = { package = "gstreamer", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-app = { package = "gstreamer-app", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-app = { package = "gstreamer-app", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-audio = { package = "gstreamer-audio", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-audio = { package = "gstreamer-audio", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-base = { package = "gstreamer-base", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-base = { package = "gstreamer-base", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-check = { package = "gstreamer-check", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-check = { package = "gstreamer-check", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-gl = { package = "gstreamer-gl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-gl = { package = "gstreamer-gl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-gl-egl = { package = "gstreamer-gl-egl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-gl-egl = { package = "gstreamer-gl-egl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-gl-wayland = { package = "gstreamer-gl-wayland", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-gl-wayland = { package = "gstreamer-gl-wayland", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-gl-x11 = { package = "gstreamer-gl-x11", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-gl-x11 = { package = "gstreamer-gl-x11", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-net = { package = "gstreamer-net", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-net = { package = "gstreamer-net", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-pbutils = { package = "gstreamer-pbutils", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-pbutils = { package = "gstreamer-pbutils", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-plugin-version-helper = { path="./version-helper" }
|
gst-plugin-version-helper = { path="./version-helper", version = "0.8" }
|
||||||
gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-rtp = { package = "gstreamer-rtp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-sdp = { package = "gstreamer-sdp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-sdp = { package = "gstreamer-sdp", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-utils = { package = "gstreamer-utils", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-utils = { package = "gstreamer-utils", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-video = { package = "gstreamer-video", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-video = { package = "gstreamer-video", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
gst-webrtc = { package = "gstreamer-webrtc", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "main" }
|
gst-webrtc = { package = "gstreamer-webrtc", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "0.22", version = "0.22" }
|
||||||
|
|
|
@ -6704,12 +6704,14 @@
|
||||||
"audio_%%u": {
|
"audio_%%u": {
|
||||||
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
},
|
},
|
||||||
"video_%%u": {
|
"video_%%u": {
|
||||||
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rank": "none"
|
"rank": "none"
|
||||||
|
@ -6735,12 +6737,14 @@
|
||||||
"audio_%%u": {
|
"audio_%%u": {
|
||||||
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
},
|
},
|
||||||
"video_%%u": {
|
"video_%%u": {
|
||||||
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rank": "none"
|
"rank": "none"
|
||||||
|
@ -6766,12 +6770,14 @@
|
||||||
"audio_%%u": {
|
"audio_%%u": {
|
||||||
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
},
|
},
|
||||||
"video_%%u": {
|
"video_%%u": {
|
||||||
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rank": "none"
|
"rank": "none"
|
||||||
|
@ -6797,12 +6803,14 @@
|
||||||
"audio_%%u": {
|
"audio_%%u": {
|
||||||
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
},
|
},
|
||||||
"video_%%u": {
|
"video_%%u": {
|
||||||
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rank": "none"
|
"rank": "none"
|
||||||
|
@ -6862,12 +6870,14 @@
|
||||||
"audio_%%u": {
|
"audio_%%u": {
|
||||||
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
"caps": "audio/x-raw:\naudio/x-opus:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
},
|
},
|
||||||
"video_%%u": {
|
"video_%%u": {
|
||||||
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
"caps": "video/x-raw:\n\nvideo/x-raw(memory:CUDAMemory):\n\nvideo/x-raw(memory:GLMemory):\n\nvideo/x-raw(memory:NVMM):\n\nvideo/x-raw(memory:D3D11Memory):\nvideo/x-vp8:\nvideo/x-h264:\nvideo/x-vp9:\nvideo/x-h265:\n",
|
||||||
"direction": "sink",
|
"direction": "sink",
|
||||||
"presence": "request"
|
"presence": "request",
|
||||||
|
"type": "GstWebRTCSinkPad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rank": "none"
|
"rank": "none"
|
||||||
|
@ -7590,6 +7600,32 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"GstWebRTCSinkPad": {
|
||||||
|
"hierarchy": [
|
||||||
|
"GstWebRTCSinkPad",
|
||||||
|
"GstGhostPad",
|
||||||
|
"GstProxyPad",
|
||||||
|
"GstPad",
|
||||||
|
"GstObject",
|
||||||
|
"GInitiallyUnowned",
|
||||||
|
"GObject"
|
||||||
|
],
|
||||||
|
"kind": "object",
|
||||||
|
"properties": {
|
||||||
|
"msid": {
|
||||||
|
"blurb": "Remote MediaStream ID in use for this pad",
|
||||||
|
"conditionally-available": false,
|
||||||
|
"construct": false,
|
||||||
|
"construct-only": false,
|
||||||
|
"controllable": false,
|
||||||
|
"default": "NULL",
|
||||||
|
"mutable": "ready",
|
||||||
|
"readable": true,
|
||||||
|
"type": "gchararray",
|
||||||
|
"writable": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"GstWebRTCSrcPad": {
|
"GstWebRTCSrcPad": {
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"GstWebRTCSrcPad",
|
"GstWebRTCSrcPad",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
project('gst-plugins-rs',
|
project('gst-plugins-rs',
|
||||||
'rust',
|
'rust',
|
||||||
'c',
|
'c',
|
||||||
version: '0.12.0-alpha.1',
|
version: '0.12.1',
|
||||||
meson_version : '>= 1.1')
|
meson_version : '>= 1.1')
|
||||||
|
|
||||||
# dependencies.py needs a toml parsing module
|
# dependencies.py needs a toml parsing module
|
||||||
|
|
|
@ -25,11 +25,11 @@ futures = "0.3"
|
||||||
tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread", "time"] }
|
tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread", "time"] }
|
||||||
tokio-native-tls = "0.3.0"
|
tokio-native-tls = "0.3.0"
|
||||||
tokio-stream = "0.1.11"
|
tokio-stream = "0.1.11"
|
||||||
async-tungstenite = { version = "0.24", features = ["tokio-runtime", "tokio-native-tls"] }
|
async-tungstenite = { version = "0.25", features = ["tokio-runtime", "tokio-native-tls"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
fastrand = "2.0"
|
fastrand = "2.0"
|
||||||
gst_plugin_webrtc_protocol = { path="protocol", package = "gst-plugin-webrtc-signalling-protocol" }
|
gst_plugin_webrtc_protocol = { path="protocol", package = "gst-plugin-webrtc-signalling-protocol", version = "0.12" }
|
||||||
human_bytes = "0.4"
|
human_bytes = "0.4"
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ rust-version.workspace = true
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
tokio = { version = "1", features = ["fs", "io-util", "macros", "rt-multi-thread", "time"] }
|
tokio = { version = "1", features = ["fs", "io-util", "macros", "rt-multi-thread", "time"] }
|
||||||
tokio-native-tls = "0.3.0"
|
tokio-native-tls = "0.3.0"
|
||||||
async-tungstenite = { version = "0.24", features = ["tokio-runtime", "tokio-native-tls"] }
|
async-tungstenite = { version = "0.25", features = ["tokio-runtime", "tokio-native-tls"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
@ -24,7 +24,7 @@ uuid = { version = "1", features = ["v4"] }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
test-log = { version = "0.2", features = ["trace"], default-features = false }
|
test-log = { version = "0.2", features = ["trace"], default-features = false }
|
||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
gst_plugin_webrtc_protocol = { path="../protocol", package = "gst-plugin-webrtc-signalling-protocol" }
|
gst_plugin_webrtc_protocol = { path="../protocol", package = "gst-plugin-webrtc-signalling-protocol", version = "0.12" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "gst-webrtc-signalling-server"
|
name = "gst-webrtc-signalling-server"
|
||||||
|
|
|
@ -20,7 +20,9 @@ use std::ops::Mul;
|
||||||
use std::sync::{mpsc, Arc, Condvar, Mutex};
|
use std::sync::{mpsc, Arc, Condvar, Mutex};
|
||||||
|
|
||||||
use super::homegrown_cc::CongestionController;
|
use super::homegrown_cc::CongestionController;
|
||||||
use super::{WebRTCSinkCongestionControl, WebRTCSinkError, WebRTCSinkMitigationMode};
|
use super::{
|
||||||
|
WebRTCSinkCongestionControl, WebRTCSinkError, WebRTCSinkMitigationMode, WebRTCSinkPad,
|
||||||
|
};
|
||||||
use crate::aws_kvs_signaller::AwsKvsSignaller;
|
use crate::aws_kvs_signaller::AwsKvsSignaller;
|
||||||
use crate::janusvr_signaller::JanusVRSignaller;
|
use crate::janusvr_signaller::JanusVRSignaller;
|
||||||
use crate::livekit_signaller::LiveKitSignaller;
|
use crate::livekit_signaller::LiveKitSignaller;
|
||||||
|
@ -186,7 +188,7 @@ impl futures::stream::FusedStream for CustomBusStream {
|
||||||
/// Wrapper around our sink pads
|
/// Wrapper around our sink pads
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct InputStream {
|
struct InputStream {
|
||||||
sink_pad: gst::GhostPad,
|
sink_pad: WebRTCSinkPad,
|
||||||
producer: Option<StreamProducer>,
|
producer: Option<StreamProducer>,
|
||||||
/// The (fixed) caps coming in
|
/// The (fixed) caps coming in
|
||||||
in_caps: Option<gst::Caps>,
|
in_caps: Option<gst::Caps>,
|
||||||
|
@ -1434,6 +1436,10 @@ impl InputStream {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn msid(&self) -> Option<String> {
|
||||||
|
self.sink_pad.property("msid")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavigationEventHandler {
|
impl NavigationEventHandler {
|
||||||
|
@ -1738,6 +1744,11 @@ impl BaseWebRTCSink {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(msid) = stream.msid() {
|
||||||
|
gst::trace!(CAT, obj: element, "forwarding msid={msid:?} to webrtcbin sinkpad");
|
||||||
|
pad.set_property("msid", &msid);
|
||||||
|
}
|
||||||
|
|
||||||
let transceiver = pad.property::<gst_webrtc::WebRTCRTPTransceiver>("transceiver");
|
let transceiver = pad.property::<gst_webrtc::WebRTCRTPTransceiver>("transceiver");
|
||||||
|
|
||||||
transceiver.set_property(
|
transceiver.set_property(
|
||||||
|
@ -4071,11 +4082,12 @@ impl ElementImpl for BaseWebRTCSink {
|
||||||
caps_builder = caps_builder.structure(codec.caps.structure(0).unwrap().to_owned());
|
caps_builder = caps_builder.structure(codec.caps.structure(0).unwrap().to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
let video_pad_template = gst::PadTemplate::new(
|
let video_pad_template = gst::PadTemplate::with_gtype(
|
||||||
"video_%u",
|
"video_%u",
|
||||||
gst::PadDirection::Sink,
|
gst::PadDirection::Sink,
|
||||||
gst::PadPresence::Request,
|
gst::PadPresence::Request,
|
||||||
&caps_builder.build(),
|
&caps_builder.build(),
|
||||||
|
WebRTCSinkPad::static_type(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -4084,11 +4096,12 @@ impl ElementImpl for BaseWebRTCSink {
|
||||||
for codec in Codecs::audio_codecs() {
|
for codec in Codecs::audio_codecs() {
|
||||||
caps_builder = caps_builder.structure(codec.caps.structure(0).unwrap().to_owned());
|
caps_builder = caps_builder.structure(codec.caps.structure(0).unwrap().to_owned());
|
||||||
}
|
}
|
||||||
let audio_pad_template = gst::PadTemplate::new(
|
let audio_pad_template = gst::PadTemplate::with_gtype(
|
||||||
"audio_%u",
|
"audio_%u",
|
||||||
gst::PadDirection::Sink,
|
gst::PadDirection::Sink,
|
||||||
gst::PadPresence::Request,
|
gst::PadPresence::Request,
|
||||||
&caps_builder.build(),
|
&caps_builder.build(),
|
||||||
|
WebRTCSinkPad::static_type(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -4127,13 +4140,13 @@ impl ElementImpl for BaseWebRTCSink {
|
||||||
(name, false)
|
(name, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let sink_pad = gst::GhostPad::builder_from_template(templ)
|
let sink_pad = gst::PadBuilder::<WebRTCSinkPad>::from_template(templ)
|
||||||
.name(name.as_str())
|
.name(name.as_str())
|
||||||
.chain_function(|pad, parent, buffer| {
|
.chain_function(|pad, parent, buffer| {
|
||||||
BaseWebRTCSink::catch_panic_pad_function(
|
BaseWebRTCSink::catch_panic_pad_function(
|
||||||
parent,
|
parent,
|
||||||
|| Err(gst::FlowError::Error),
|
|| Err(gst::FlowError::Error),
|
||||||
|this| this.chain(pad, buffer),
|
|this| this.chain(pad.upcast_ref(), buffer),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.event_function(|pad, parent, event| {
|
.event_function(|pad, parent, event| {
|
||||||
|
@ -4250,7 +4263,7 @@ impl ChildProxyImpl for BaseWebRTCSink {
|
||||||
fn child_by_name(&self, name: &str) -> Option<glib::Object> {
|
fn child_by_name(&self, name: &str) -> Option<glib::Object> {
|
||||||
match name {
|
match name {
|
||||||
"signaller" => Some(self.settings.lock().unwrap().signaller.clone().upcast()),
|
"signaller" => Some(self.settings.lock().unwrap().signaller.clone().upcast()),
|
||||||
_ => None,
|
_ => self.obj().static_pad(name).map(|pad| pad.upcast()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,16 @@ use gst::subclass::prelude::*;
|
||||||
mod homegrown_cc;
|
mod homegrown_cc;
|
||||||
|
|
||||||
mod imp;
|
mod imp;
|
||||||
|
mod pad;
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct BaseWebRTCSink(ObjectSubclass<imp::BaseWebRTCSink>) @extends gst::Bin, gst::Element, gst::Object, @implements gst::ChildProxy, gst_video::Navigation;
|
pub struct BaseWebRTCSink(ObjectSubclass<imp::BaseWebRTCSink>) @extends gst::Bin, gst::Element, gst::Object, @implements gst::ChildProxy, gst_video::Navigation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct WebRTCSinkPad(ObjectSubclass<pad::WebRTCSinkPad>) @extends gst::GhostPad, gst::ProxyPad, gst::Pad, gst::Object;
|
||||||
|
}
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct WebRTCSink(ObjectSubclass<imp::WebRTCSink>) @extends BaseWebRTCSink, gst::Bin, gst::Element, gst::Object, @implements gst::ChildProxy, gst_video::Navigation;
|
pub struct WebRTCSink(ObjectSubclass<imp::WebRTCSink>) @extends BaseWebRTCSink, gst::Bin, gst::Element, gst::Object, @implements gst::ChildProxy, gst_video::Navigation;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +129,7 @@ enum WebRTCSinkMitigationMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
|
WebRTCSinkPad::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
||||||
BaseWebRTCSink::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
BaseWebRTCSink::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
||||||
WebRTCSinkCongestionControl::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
WebRTCSinkCongestionControl::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
|
||||||
gst::Element::register(
|
gst::Element::register(
|
||||||
|
|
57
net/webrtc/src/webrtcsink/pad.rs
Normal file
57
net/webrtc/src/webrtcsink/pad.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use gst::{glib, prelude::*, subclass::prelude::*};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WebRTCSinkPad {
|
||||||
|
settings: Mutex<Settings>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Settings {
|
||||||
|
msid: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for WebRTCSinkPad {
|
||||||
|
const NAME: &'static str = "GstWebRTCSinkPad";
|
||||||
|
type Type = super::WebRTCSinkPad;
|
||||||
|
type ParentType = gst::GhostPad;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for WebRTCSinkPad {
|
||||||
|
fn properties() -> &'static [glib::ParamSpec] {
|
||||||
|
static PROPS: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||||
|
vec![glib::ParamSpecString::builder("msid")
|
||||||
|
.flags(glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY)
|
||||||
|
.blurb("Remote MediaStream ID in use for this pad")
|
||||||
|
.build()]
|
||||||
|
});
|
||||||
|
PROPS.as_ref()
|
||||||
|
}
|
||||||
|
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||||
|
let mut settings = self.settings.lock().unwrap();
|
||||||
|
match pspec.name() {
|
||||||
|
"msid" => {
|
||||||
|
settings.msid = value
|
||||||
|
.get::<Option<String>>()
|
||||||
|
.expect("type checked upstream")
|
||||||
|
}
|
||||||
|
name => panic!("no writable property {name:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||||
|
let settings = self.settings.lock().unwrap();
|
||||||
|
match pspec.name() {
|
||||||
|
"msid" => settings.msid.to_value(),
|
||||||
|
name => panic!("no readable property {name:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GstObjectImpl for WebRTCSinkPad {}
|
||||||
|
impl PadImpl for WebRTCSinkPad {}
|
||||||
|
impl ProxyPadImpl for WebRTCSinkPad {}
|
||||||
|
impl GhostPadImpl for WebRTCSinkPad {}
|
|
@ -174,7 +174,7 @@ impl TextWrap {
|
||||||
CAT,
|
CAT,
|
||||||
imp: self,
|
imp: self,
|
||||||
"Outputting contents {}, ts: {}, duration: {}",
|
"Outputting contents {}, ts: {}, duration: {}",
|
||||||
drained.to_string(),
|
drained,
|
||||||
state.start_ts.display(),
|
state.start_ts.display(),
|
||||||
duration.display(),
|
duration.display(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,7 @@ gst.workspace = true
|
||||||
gst-base.workspace = true
|
gst-base.workspace = true
|
||||||
gst-audio.workspace = true
|
gst-audio.workspace = true
|
||||||
gst-video.workspace = true
|
gst-video.workspace = true
|
||||||
gst-plugin-gtk4 = { path = "../../video/gtk4", optional = true }
|
gst-plugin-gtk4 = { path = "../../video/gtk4", optional = true, version = "0.12" }
|
||||||
gtk = { workspace = true, optional = true }
|
gtk = { workspace = true, optional = true }
|
||||||
gio = { workspace = true, optional = true }
|
gio = { workspace = true, optional = true }
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
|
|
|
@ -534,7 +534,7 @@ impl ObjectImpl for FallbackSrc {
|
||||||
|
|
||||||
// Called whenever a value of a property is read. It can be called
|
// Called whenever a value of a property is read. It can be called
|
||||||
// at any time from any thread.
|
// at any time from any thread.
|
||||||
#[allow(clippy::blocks_in_if_conditions)]
|
#[allow(clippy::block_in_conditions)]
|
||||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||||
match pspec.name() {
|
match pspec.name() {
|
||||||
"enable-audio" => {
|
"enable-audio" => {
|
||||||
|
@ -3237,7 +3237,7 @@ impl FallbackSrc {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::blocks_in_if_conditions)]
|
#[allow(clippy::block_in_conditions)]
|
||||||
fn schedule_source_restart_timeout(
|
fn schedule_source_restart_timeout(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
|
@ -3400,7 +3400,7 @@ impl FallbackSrc {
|
||||||
source.restart_timeout = Some(timeout);
|
source.restart_timeout = Some(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::blocks_in_if_conditions)]
|
#[allow(clippy::block_in_conditions)]
|
||||||
fn have_fallback_activated(&self, state: &State) -> bool {
|
fn have_fallback_activated(&self, state: &State) -> bool {
|
||||||
let mut have_audio = false;
|
let mut have_audio = false;
|
||||||
let mut have_video = false;
|
let mut have_video = false;
|
||||||
|
|
|
@ -771,7 +771,7 @@ impl FallbackSwitch {
|
||||||
is_active
|
is_active
|
||||||
);
|
);
|
||||||
|
|
||||||
#[allow(clippy::blocks_in_if_conditions)]
|
#[allow(clippy::block_in_conditions)]
|
||||||
let output_clockid = if is_active {
|
let output_clockid = if is_active {
|
||||||
pad_state.schedule_clock(
|
pad_state.schedule_clock(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -12,7 +12,7 @@ rust-version.workspace = true
|
||||||
gio = { workspace = true, optional = true }
|
gio = { workspace = true, optional = true }
|
||||||
gst.workspace = true
|
gst.workspace = true
|
||||||
gst-audio.workspace = true
|
gst-audio.workspace = true
|
||||||
gst-plugin-gtk4 = { path = "../../video/gtk4", optional = true }
|
gst-plugin-gtk4 = { path = "../../video/gtk4", optional = true, version = "0.12" }
|
||||||
gtk = { workspace = true, optional = true }
|
gtk = { workspace = true, optional = true }
|
||||||
num-rational = { version = "0.4", default-features = false, features = [] }
|
num-rational = { version = "0.4", default-features = false, features = [] }
|
||||||
once_cell.workspace = true
|
once_cell.workspace = true
|
||||||
|
|
|
@ -12,7 +12,7 @@ rust-version.workspace = true
|
||||||
gst.workspace = true
|
gst.workspace = true
|
||||||
gst-audio.workspace = true
|
gst-audio.workspace = true
|
||||||
gst-video.workspace = true
|
gst-video.workspace = true
|
||||||
gst-plugin-gtk4 = { path = "../../video/gtk4", optional = true }
|
gst-plugin-gtk4 = { path = "../../video/gtk4", optional = true, version = "0.12" }
|
||||||
gtk = { workspace = true, optional = true }
|
gtk = { workspace = true, optional = true }
|
||||||
gio = { workspace = true, optional = true }
|
gio = { workspace = true, optional = true }
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
|
|
|
@ -693,7 +693,7 @@ impl ToggleRecord {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::blocks_in_if_conditions)]
|
#[allow(clippy::block_in_conditions)]
|
||||||
fn handle_secondary_stream<T: HandleData>(
|
fn handle_secondary_stream<T: HandleData>(
|
||||||
&self,
|
&self,
|
||||||
pad: &gst::Pad,
|
pad: &gst::Pad,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "gst-plugin-version-helper"
|
name = "gst-plugin-version-helper"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
authors = ["Sajeer Ahamed <ahamedsajeer.15.15@cse.mrt.ac.lk>",
|
authors = ["Sajeer Ahamed <ahamedsajeer.15.15@cse.mrt.ac.lk>",
|
||||||
"Sebastian Dröge <sebastian@centricular.com>"]
|
"Sebastian Dröge <sebastian@centricular.com>"]
|
||||||
categories = ["development-tools"]
|
categories = ["development-tools"]
|
||||||
|
|
|
@ -61,6 +61,7 @@ pub(crate) static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PaintableSink {
|
pub struct PaintableSink {
|
||||||
paintable: Mutex<Option<ThreadGuard<Paintable>>>,
|
paintable: Mutex<Option<ThreadGuard<Paintable>>>,
|
||||||
|
window: Mutex<Option<ThreadGuard<gtk::Window>>>,
|
||||||
info: Mutex<Option<gst_video::VideoInfo>>,
|
info: Mutex<Option<gst_video::VideoInfo>>,
|
||||||
sender: Mutex<Option<async_channel::Sender<SinkEvent>>>,
|
sender: Mutex<Option<async_channel::Sender<SinkEvent>>>,
|
||||||
pending_frame: Mutex<Option<Frame>>,
|
pending_frame: Mutex<Option<Frame>>,
|
||||||
|
@ -231,6 +232,18 @@ impl ElementImpl for PaintableSink {
|
||||||
) -> Result<gst::StateChangeSuccess, gst::StateChangeError> {
|
) -> Result<gst::StateChangeSuccess, gst::StateChangeError> {
|
||||||
match transition {
|
match transition {
|
||||||
gst::StateChange::NullToReady => {
|
gst::StateChange::NullToReady => {
|
||||||
|
let create_window = glib::program_name().as_deref() == Some("gst-launch-1.0")
|
||||||
|
|| std::env::var("GST_GTK4_WINDOW").as_deref() == Ok("1");
|
||||||
|
|
||||||
|
if create_window {
|
||||||
|
let res = utils::invoke_on_main_thread(gtk::init);
|
||||||
|
|
||||||
|
if let Err(err) = res {
|
||||||
|
gst::error!(CAT, imp: self, "Failed to create initialize GTK: {err}");
|
||||||
|
return Err(gst::StateChangeError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut paintable = self.paintable.lock().unwrap();
|
let mut paintable = self.paintable.lock().unwrap();
|
||||||
|
|
||||||
if paintable.is_none() {
|
if paintable.is_none() {
|
||||||
|
@ -273,6 +286,10 @@ impl ElementImpl for PaintableSink {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if create_window {
|
||||||
|
self.create_window();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -294,6 +311,17 @@ impl ElementImpl for PaintableSink {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
gst::StateChange::ReadyToNull => {
|
||||||
|
let mut window_guard = self.window.lock().unwrap();
|
||||||
|
if let Some(window) = window_guard.take() {
|
||||||
|
drop(window_guard);
|
||||||
|
|
||||||
|
glib::MainContext::default().invoke(move || {
|
||||||
|
let window = window.get_ref();
|
||||||
|
window.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +548,46 @@ impl PaintableSink {
|
||||||
.replace(tmp_caps);
|
.replace(tmp_caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_window(&self) {
|
||||||
|
let self_ = self.to_owned();
|
||||||
|
glib::MainContext::default().invoke(move || {
|
||||||
|
let mut window_guard = self_.window.lock().unwrap();
|
||||||
|
if window_guard.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let paintable = match &*self_.paintable.lock().unwrap() {
|
||||||
|
Some(paintable) => paintable.get_ref().clone(),
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let window = gtk::Window::new();
|
||||||
|
let picture = gtk::Picture::new();
|
||||||
|
picture.set_paintable(Some(&paintable));
|
||||||
|
window.set_child(Some(&picture));
|
||||||
|
window.set_default_size(640, 480);
|
||||||
|
|
||||||
|
window.connect_close_request({
|
||||||
|
let self_ = self_.clone();
|
||||||
|
move |_window| {
|
||||||
|
if self_.window.lock().unwrap().is_some() {
|
||||||
|
gst::element_imp_error!(
|
||||||
|
self_,
|
||||||
|
gst::ResourceError::NotFound,
|
||||||
|
("Output window was closed")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::Propagation::Proceed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
*window_guard = Some(ThreadGuard::new(window));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn create_paintable(&self, paintable_storage: &mut MutexGuard<Option<ThreadGuard<Paintable>>>) {
|
fn create_paintable(&self, paintable_storage: &mut MutexGuard<Option<ThreadGuard<Paintable>>>) {
|
||||||
#[cfg(any(target_os = "macos", target_os = "windows", feature = "gst-gl"))]
|
#[cfg(any(target_os = "macos", target_os = "windows", feature = "gst-gl"))]
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue