feat: Update iced_video_player to master

This commit is contained in:
uttarayan21
2025-12-13 03:40:12 +05:30
parent c7afcd3f0d
commit 253d27c176
18 changed files with 1224 additions and 1565 deletions

231
Cargo.lock generated
View File

@@ -1665,7 +1665,8 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]] [[package]]
name = "cryoglyph" name = "cryoglyph"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/iced-rs/cryoglyph.git?rev=99b46959369f38a06c11353bf1be81d383b289fc#99b46959369f38a06c11353bf1be81d383b289fc" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08bc795bdbccdbd461736fb163930a009da6597b226d6f6fce33e7a8eb6ec519"
dependencies = [ dependencies = [
"cosmic-text 0.15.0", "cosmic-text 0.15.0",
"etagere", "etagere",
@@ -1858,47 +1859,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]] [[package]]
name = "dpi" name = "dpi"
version = "0.1.1" version = "0.1.2"
source = "git+https://github.com/iced-rs/winit.git?rev=05b8ff17a06562f0a10bb46e6eaacbe2a95cb5ed#05b8ff17a06562f0a10bb46e6eaacbe2a95cb5ed"
[[package]]
name = "drm"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
dependencies = [
"bitflags 2.10.0",
"bytemuck",
"drm-ffi",
"drm-fourcc",
"rustix 0.38.44",
]
[[package]]
name = "drm-ffi"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53"
dependencies = [
"drm-sys",
"rustix 0.38.44",
]
[[package]]
name = "drm-fourcc"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
[[package]]
name = "drm-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986"
dependencies = [
"libc",
"linux-raw-sys 0.6.5",
]
[[package]] [[package]]
name = "dtor" name = "dtor"
@@ -2557,15 +2520,15 @@ checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]] [[package]]
name = "gio-sys" name = "gio-sys"
version = "0.21.2" version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "171ed2f6dd927abbe108cfd9eebff2052c335013f5879d55bab0dc1dee19b706" checksum = "521e93a7e56fc89e84aea9a52cfc9436816a4b363b030260b699950ff1336c83"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps", "system-deps",
"windows-sys 0.61.2", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -2587,9 +2550,9 @@ checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
[[package]] [[package]]
name = "glib" name = "glib"
version = "0.21.4" version = "0.20.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9dbecb1c33e483a98be4acfea2ab369e1c28f517c6eadb674537409c25c4b2" checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683"
dependencies = [ dependencies = [
"bitflags 2.10.0", "bitflags 2.10.0",
"futures-channel", "futures-channel",
@@ -2608,9 +2571,9 @@ dependencies = [
[[package]] [[package]]
name = "glib-macros" name = "glib-macros"
version = "0.21.4" version = "0.20.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "880e524e0085f3546cfb38532b2c202c0d64741d9977a6e4aa24704bfc9f19fb" checksum = "e8084af62f09475a3f529b1629c10c429d7600ee1398ae12dd3bf175d74e7145"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro-crate", "proc-macro-crate",
@@ -2621,9 +2584,9 @@ dependencies = [
[[package]] [[package]]
name = "glib-sys" name = "glib-sys"
version = "0.21.2" version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09d3d0fddf7239521674e57b0465dfbd844632fec54f059f7f56112e3f927e1" checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215"
dependencies = [ dependencies = [
"libc", "libc",
"system-deps", "system-deps",
@@ -2683,9 +2646,9 @@ dependencies = [
[[package]] [[package]]
name = "gobject-sys" name = "gobject-sys"
version = "0.21.2" version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "538e41d8776173ec107e7b0f2aceced60abc368d7e1d81c1f0e2ecd35f59080d" checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
@@ -3016,9 +2979,9 @@ checksum = "12101ecc8225ea6d675bc70263074eab6169079621c2186fe0c66590b2df9681"
[[package]] [[package]]
name = "gstreamer" name = "gstreamer"
version = "0.24.3" version = "0.23.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ac2f12970a2f85a681d2ceaa40c32fe86cc202ead315e0dfa2223a1217cd24" checksum = "8757a87f3706560037a01a9f06a59fcc7bdb0864744dcf73546606e60c4316e1"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"futures-channel", "futures-channel",
@@ -3027,13 +2990,13 @@ dependencies = [
"glib", "glib",
"gstreamer-sys", "gstreamer-sys",
"itertools 0.14.0", "itertools 0.14.0",
"kstring",
"libc", "libc",
"muldiv", "muldiv",
"num-integer", "num-integer",
"num-rational", "num-rational",
"once_cell",
"option-operations", "option-operations",
"pastey", "paste",
"pin-project-lite", "pin-project-lite",
"smallvec", "smallvec",
"thiserror 2.0.17", "thiserror 2.0.17",
@@ -3041,9 +3004,9 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer-app" name = "gstreamer-app"
version = "0.24.2" version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0af5d403738faf03494dfd502d223444b4b44feb997ba28ab3f118ee6d40a0b2" checksum = "2e9a883eb21aebcf1289158225c05f7aea5da6ecf71fa7f0ff1ce4d25baf004e"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@@ -3056,9 +3019,9 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer-app-sys" name = "gstreamer-app-sys"
version = "0.24.0" version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf1a3af017f9493c34ccc8439cbce5c48f6ddff6ec0514c23996b374ff25f9a" checksum = "94f7ef838306fe51852d503a14dc79ac42de005a59008a05098de3ecdaf05455"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"gstreamer-base-sys", "gstreamer-base-sys",
@@ -3069,9 +3032,9 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer-base" name = "gstreamer-base"
version = "0.24.2" version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71ff9b0bbc8041f0c6c8a53b206a6542f86c7d9fa8a7dff3f27d9c374d9f39b4" checksum = "f19a74fd04ffdcb847dd322640f2cf520897129d00a7bcb92fd62a63f3e27404"
dependencies = [ dependencies = [
"atomic_refcell", "atomic_refcell",
"cfg-if", "cfg-if",
@@ -3083,9 +3046,9 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer-base-sys" name = "gstreamer-base-sys"
version = "0.24.2" version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed78852b92db1459b8f4288f86e6530274073c20be2f94ba642cddaca08b00e" checksum = "87f2fb0037b6d3c5b51f60dea11e667910f33be222308ca5a101450018a09840"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
@@ -3096,17 +3059,47 @@ dependencies = [
[[package]] [[package]]
name = "gstreamer-sys" name = "gstreamer-sys"
version = "0.24.2" version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a24ae2930e683665832a19ef02466094b09d1f2da5673f001515ed5486aa9377" checksum = "feea73b4d92dbf9c24a203c9cd0bcc740d584f6b5960d5faf359febf288919b2"
dependencies = [ dependencies = [
"cfg-if",
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps", "system-deps",
] ]
[[package]]
name = "gstreamer-video"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1318b599d77ca4f7702ecbdeac1672d6304cb16b7e5752fabb3ee8260449a666"
dependencies = [
"cfg-if",
"futures-channel",
"glib",
"gstreamer",
"gstreamer-base",
"gstreamer-video-sys",
"libc",
"once_cell",
"thiserror 2.0.17",
]
[[package]]
name = "gstreamer-video-sys"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a70f0947f12d253b9de9bc3fd92f981e4d025336c18389c7f08cdf388a99f5c"
dependencies = [
"glib-sys",
"gobject-sys",
"gstreamer-base-sys",
"gstreamer-sys",
"libc",
"system-deps",
]
[[package]] [[package]]
name = "guillotiere" name = "guillotiere"
version = "0.6.2" version = "0.6.2"
@@ -3376,8 +3369,9 @@ dependencies = [
[[package]] [[package]]
name = "iced" name = "iced"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000e01026c93ba643f8357a3db3ada0e6555265a377f6f9291c472f6dd701fb3"
dependencies = [ dependencies = [
"iced_core", "iced_core",
"iced_debug", "iced_debug",
@@ -3393,8 +3387,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_beacon" name = "iced_beacon"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02a48f970444257a5e8b19def673f14f0d79c159fa851055e2a861683c3f8845"
dependencies = [ dependencies = [
"bincode", "bincode",
"futures", "futures",
@@ -3408,8 +3403,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_core" name = "iced_core"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ab1937d699403e7e69252ae743a902bcee9f4ab2052cc4c9a46fcf34729d85"
dependencies = [ dependencies = [
"bitflags 2.10.0", "bitflags 2.10.0",
"bytes", "bytes",
@@ -3426,8 +3422,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_debug" name = "iced_debug"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25035ab0215a620e53f4103e36fc4e59a1fb2817e4bfc38a30ad27b4202ea0be"
dependencies = [ dependencies = [
"iced_beacon", "iced_beacon",
"iced_core", "iced_core",
@@ -3437,8 +3434,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_devtools" name = "iced_devtools"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b8e2a306ac5c583234b02f5404afdb7b7467c8f72a4a44ad3e7be30fc4b339"
dependencies = [ dependencies = [
"iced_debug", "iced_debug",
"iced_program", "iced_program",
@@ -3448,8 +3446,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_futures" name = "iced_futures"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c0c85ccad42dfbec7293c36c018af0ea0dbcc52d137a4a9a0b0f6822a3fdf0a"
dependencies = [ dependencies = [
"futures", "futures",
"iced_core", "iced_core",
@@ -3462,8 +3461,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_graphics" name = "iced_graphics"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234ca1c2cec4155055f68fa5fad1b5242c496ac8238d80a259bca382fb44a102"
dependencies = [ dependencies = [
"bitflags 2.10.0", "bitflags 2.10.0",
"bytemuck", "bytemuck",
@@ -3483,8 +3483,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_program" name = "iced_program"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dfafec2947cda688d8eb00dac337ba11aa60f9ef6335aed343e189d26e4a673"
dependencies = [ dependencies = [
"iced_graphics", "iced_graphics",
"iced_runtime", "iced_runtime",
@@ -3492,8 +3493,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_renderer" name = "iced_renderer"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "250cc0802408e8c077986ec56c7d07c65f423ee658a4b9fd795a1f2aae5dac05"
dependencies = [ dependencies = [
"iced_graphics", "iced_graphics",
"iced_tiny_skia", "iced_tiny_skia",
@@ -3504,8 +3506,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_runtime" name = "iced_runtime"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1889b819ce4c06674183242e336c8d49465665441396914dc07cc86f44fa8d4"
dependencies = [ dependencies = [
"bytes", "bytes",
"iced_core", "iced_core",
@@ -3517,8 +3520,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_tiny_skia" name = "iced_tiny_skia"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0acf8b75a3bc914aff5f2329fdffc1b36eeaea29dda0e4bd232f1c62e9cc3d"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"cosmic-text 0.15.0", "cosmic-text 0.15.0",
@@ -3539,17 +3543,19 @@ dependencies = [
"gstreamer", "gstreamer",
"gstreamer-app", "gstreamer-app",
"gstreamer-base", "gstreamer-base",
"gstreamer-video",
"iced", "iced",
"iced_wgpu", "iced_wgpu",
"log", "log",
"thiserror 2.0.17", "thiserror 1.0.69",
"url", "url",
] ]
[[package]] [[package]]
name = "iced_wgpu" name = "iced_wgpu"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff144a999b0ca0f8a10257934500060240825c42e950ec0ebee9c8ae30561c13"
dependencies = [ dependencies = [
"bitflags 2.10.0", "bitflags 2.10.0",
"bytemuck", "bytemuck",
@@ -3568,8 +3574,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_widget" name = "iced_widget"
version = "0.14.0-dev" version = "0.14.1"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86f6948998a5e031849afae1bb852f3b100c71572befa0be70b19075dcb2163"
dependencies = [ dependencies = [
"iced_renderer", "iced_renderer",
"log", "log",
@@ -3581,8 +3588,9 @@ dependencies = [
[[package]] [[package]]
name = "iced_winit" name = "iced_winit"
version = "0.14.0-dev" version = "0.14.0"
source = "git+https://github.com/iced-rs/iced#8bfd099c5929d927a3fdde666d4c645d0bd83cb7" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7dbedc47562d1de3b9707d939f678b88c382004b7ab5a18f7a7dd723162d75"
dependencies = [ dependencies = [
"iced_debug", "iced_debug",
"iced_program", "iced_program",
@@ -4041,15 +4049,6 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kstring"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1"
dependencies = [
"static_assertions",
]
[[package]] [[package]]
name = "kurbo" name = "kurbo"
version = "0.10.4" version = "0.10.4"
@@ -4174,12 +4173,6 @@ version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.11.0" version = "0.11.0"
@@ -5309,11 +5302,11 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]] [[package]]
name = "option-operations" name = "option-operations"
version = "0.6.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b31ce827892359f23d3cd1cc4c75a6c241772bbd2db17a92dcf27cbefdf52689" checksum = "7c26d27bb1aeab65138e4bf7666045169d1717febcc9ff870166be8348b223d0"
dependencies = [ dependencies = [
"pastey", "paste",
] ]
[[package]] [[package]]
@@ -6855,7 +6848,6 @@ dependencies = [
"bytemuck", "bytemuck",
"cfg_aliases", "cfg_aliases",
"core-graphics 0.24.0", "core-graphics 0.24.0",
"drm",
"fastrand 2.3.0", "fastrand 2.3.0",
"foreign-types 0.5.0", "foreign-types 0.5.0",
"js-sys", "js-sys",
@@ -8592,9 +8584,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "window_clipboard" name = "window_clipboard"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6d692d46038c433f9daee7ad8757e002a4248c20b0a3fbc991d99521d3bcb6d" checksum = "5793d0b08c9e6a1240fe9ab2bd8db277487bf92436fd1a6321861a90a1b0cb7e"
dependencies = [ dependencies = [
"clipboard-win", "clipboard-win",
"clipboard_macos", "clipboard_macos",
@@ -9208,8 +9200,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]] [[package]]
name = "winit" name = "winit"
version = "0.30.8" version = "0.30.12"
source = "git+https://github.com/iced-rs/winit.git?rev=05b8ff17a06562f0a10bb46e6eaacbe2a95cb5ed#05b8ff17a06562f0a10bb46e6eaacbe2a95cb5ed" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
dependencies = [ dependencies = [
"ahash", "ahash",
"android-activity", "android-activity",

View File

@@ -5,10 +5,12 @@ members = [
"typegen", "typegen",
"ui-gpui", "ui-gpui",
"ui-iced", "ui-iced",
"crates/iced_video_player", "store", "jello-types", "crates/iced_video_player",
"store",
"jello-types",
] ]
[workspace.dependencies] [workspace.dependencies]
iced = { git = "https://github.com/iced-rs/iced", features = [ iced = { version = "0.14.0", features = [
"advanced", "advanced",
"canvas", "canvas",
"image", "image",
@@ -16,6 +18,7 @@ iced = { git = "https://github.com/iced-rs/iced", features = [
"tokio", "tokio",
"debug", "debug",
] } ] }
# iced_video_player = { git = "https://github.com/jazzfool/iced_video_player" }
iced_video_player = { path = "crates/iced_video_player" } iced_video_player = { path = "crates/iced_video_player" }
[package] [package]

View File

@@ -1,3 +1,2 @@
/target /target
.direnv .direnv
.media

File diff suppressed because it is too large Load Diff

View File

@@ -8,24 +8,23 @@ keywords = ["gui", "iced", "video"]
categories = ["gui", "multimedia"] categories = ["gui", "multimedia"]
version = "0.6.0" version = "0.6.0"
authors = ["jazzfool"] authors = ["jazzfool"]
edition = "2021" edition = "2024"
resolver = "2" resolver = "2"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
exclude = [".media/test.mp4"] exclude = [
".media/test.mp4"
]
[dependencies] [dependencies]
iced = { git = "https://github.com/iced-rs/iced", features = [ iced = { version = "0.14", features = ["image", "advanced", "wgpu"] }
"image", iced_wgpu = "0.14"
"advanced", gstreamer = "0.23"
"wgpu", gstreamer-app = "0.23" # appsink
] } gstreamer-base = "0.23" # basesrc
iced_wgpu = { git = "https://github.com/iced-rs/iced" } gstreamer-video = "0.23" # VideoMeta
gstreamer = { version = "0.24", features = ["v1_26"] } glib = "0.20" # gobject traits and error type
gstreamer-app = { version = "0.24", features = ["v1_26"] } # appsink
gstreamer-base = { version = "0.24", features = ["v1_26"] } # basesrc
glib = "0.21" # gobject traits and error type
log = "0.4" log = "0.4"
thiserror = "2" thiserror = "1"
url = "2" # media uri url = "2" # media uri
[package.metadata.nix] [package.metadata.nix]
@@ -33,33 +32,15 @@ systems = ["x86_64-linux"]
app = true app = true
build = true build = true
runtimeLibs = [ runtimeLibs = [
"vulkan-loader", "vulkan-loader",
"wayland", "wayland",
"wayland-protocols", "wayland-protocols",
"libxkbcommon", "libxkbcommon",
"xorg.libX11", "xorg.libX11",
"xorg.libXrandr", "xorg.libXrandr",
"xorg.libXi", "xorg.libXi", "gst_all_1.gstreamer", "gst_all_1.gstreamermm", "gst_all_1.gst-plugins-bad", "gst_all_1.gst-plugins-ugly", "gst_all_1.gst-plugins-good", "gst_all_1.gst-plugins-base",
"gst_all_1.gstreamer",
"gst_all_1.gstreamermm",
"gst_all_1.gst-plugins-bad",
"gst_all_1.gst-plugins-ugly",
"gst_all_1.gst-plugins-good",
"gst_all_1.gst-plugins-base",
"glib",
"glib-networking",
]
buildInputs = [
"libxkbcommon",
"gst_all_1.gstreamer",
"gst_all_1.gstreamermm",
"gst_all_1.gst-plugins-bad",
"gst_all_1.gst-plugins-ugly",
"gst_all_1.gst-plugins-good",
"gst_all_1.gst-plugins-base",
"glib",
"glib-networking",
] ]
buildInputs = ["libxkbcommon", "gst_all_1.gstreamer", "gst_all_1.gstreamermm", "gst_all_1.gst-plugins-bad", "gst_all_1.gst-plugins-ugly", "gst_all_1.gst-plugins-good", "gst_all_1.gst-plugins-base"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"] rustc-args = ["--cfg", "docsrs"]

View File

@@ -1,6 +1,6 @@
use iced::{ use iced::{
widget::{Button, Column, Container, Row, Slider, Text},
Element, Element,
widget::{Button, Column, Container, Row, Slider, Text},
}; };
use iced_video_player::{Video, VideoPlayer}; use iced_video_player::{Video, VideoPlayer};
use std::time::Duration; use std::time::Duration;
@@ -29,10 +29,17 @@ impl Default for App {
fn default() -> Self { fn default() -> Self {
App { App {
video: Video::new( video: Video::new(
&url::Url::parse("https://jellyfin.tsuba.darksailor.dev/Videos/1d7e2012-e17d-edbb-25c3-2dbcc803d6b6/stream?static=true") &url::Url::from_file_path(
.expect("Failed to parse URL"), std::path::PathBuf::from(file!())
.parent()
.unwrap()
.join("../.media/test.mp4")
.canonicalize()
.unwrap(),
)
.unwrap(),
) )
.expect("Failed to create video"), .unwrap(),
position: 0.0, position: 0.0,
dragging: false, dragging: false,
} }

View File

@@ -1,69 +1,28 @@
{ {
"nodes": { "nodes": {
"crane": { "devshell": {
"flake": false,
"locked": { "locked": {
"lastModified": 1758758545, "lastModified": 1629275356,
"narHash": "sha256-NU5WaEdfwF6i8faJ2Yh+jcK9vVFrofLcwlD/mP65JrI=", "narHash": "sha256-R17M69EKXP6q8/mNHaK53ECwjFo1pdF+XaJC9Qq8zjg=",
"owner": "ipetkov", "owner": "numtide",
"repo": "crane", "repo": "devshell",
"rev": "95d528a5f54eaba0d12102249ce42f4d01f4e364", "rev": "26f25a12265f030917358a9632cd600b51af1d97",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "ipetkov", "owner": "numtide",
"ref": "v0.21.1", "repo": "devshell",
"repo": "crane",
"type": "github"
}
},
"dream2nix": {
"inputs": {
"nixpkgs": [
"nixCargoIntegration",
"nixpkgs"
],
"purescript-overlay": "purescript-overlay",
"pyproject-nix": "pyproject-nix"
},
"locked": {
"lastModified": 1763413832,
"narHash": "sha256-dkqBwDXiv8MPoFyIvOuC4bVubAP+TlVZUkVMB78TTSg=",
"owner": "nix-community",
"repo": "dream2nix",
"rev": "5658fba3a0b6b7d5cb0460b949651f64f644a743",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "dream2nix",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github" "type": "github"
} }
}, },
"flakeCompat": { "flakeCompat": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1761588595, "lastModified": 1627913399,
"narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", "narHash": "sha256-hY8g6H2KFL8ownSiFeMOjwPC8P0ueXpCVEbxgda3pko=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "rev": "12c64ca55c1014cdc1b16ed5a804aa8576601ff2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -72,40 +31,20 @@
"type": "github" "type": "github"
} }
}, },
"mk-naked-shell": {
"flake": false,
"locked": {
"lastModified": 1681286841,
"narHash": "sha256-3XlJrwlR0nBiREnuogoa5i1b4+w/XPe0z8bbrJASw0g=",
"owner": "90-008",
"repo": "mk-naked-shell",
"rev": "7612f828dd6f22b7fb332cc69440e839d7ffe6bd",
"type": "github"
},
"original": {
"owner": "90-008",
"repo": "mk-naked-shell",
"type": "github"
}
},
"nixCargoIntegration": { "nixCargoIntegration": {
"inputs": { "inputs": {
"crane": "crane", "devshell": "devshell",
"dream2nix": "dream2nix",
"mk-naked-shell": "mk-naked-shell",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"parts": "parts", "rustOverlay": "rustOverlay"
"rust-overlay": "rust-overlay",
"treefmt": "treefmt"
}, },
"locked": { "locked": {
"lastModified": 1763619566, "lastModified": 1629871751,
"narHash": "sha256-92rSHIwh5qTXjcktVEWyKu5EPB3/7UdgjgjtWZ5ET6w=", "narHash": "sha256-QjnDg34ApcnjmXlNLnbHswT9OroCPY7Wip6r9Zkgkfo=",
"owner": "yusdacra", "owner": "yusdacra",
"repo": "nix-cargo-integration", "repo": "nix-cargo-integration",
"rev": "ac45d8c0d6876e6547d62bc729654c7b9a79c760", "rev": "4f164ecad242537d5893426eef02c47c9e5ced59",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -116,11 +55,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1763421233, "lastModified": 1629618782,
"narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=", "narHash": "sha256-2K8SSXu3alo/URI3MClGdDSns6Gb4ZaW4LET53UWyKk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648", "rev": "870959c7fb3a42af1863bed9e1756086a74eb649",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -130,73 +69,6 @@
"type": "github" "type": "github"
} }
}, },
"parts": {
"inputs": {
"nixpkgs-lib": [
"nixCargoIntegration",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762980239,
"narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "52a2caecc898d0b46b2b905f058ccc5081f842da",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"purescript-overlay": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixCargoIntegration",
"dream2nix",
"nixpkgs"
],
"slimlock": "slimlock"
},
"locked": {
"lastModified": 1728546539,
"narHash": "sha256-Sws7w0tlnjD+Bjck1nv29NjC5DbL6nH5auL9Ex9Iz2A=",
"owner": "thomashoneyman",
"repo": "purescript-overlay",
"rev": "4ad4c15d07bd899d7346b331f377606631eb0ee4",
"type": "github"
},
"original": {
"owner": "thomashoneyman",
"repo": "purescript-overlay",
"type": "github"
}
},
"pyproject-nix": {
"inputs": {
"nixpkgs": [
"nixCargoIntegration",
"dream2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1752481895,
"narHash": "sha256-luVj97hIMpCbwhx3hWiRwjP2YvljWy8FM+4W9njDhLA=",
"owner": "pyproject-nix",
"repo": "pyproject.nix",
"rev": "16ee295c25107a94e59a7fc7f2e5322851781162",
"type": "github"
},
"original": {
"owner": "pyproject-nix",
"repo": "pyproject.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"flakeCompat": "flakeCompat", "flakeCompat": "flakeCompat",
@@ -204,19 +76,14 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
}, },
"rust-overlay": { "rustOverlay": {
"inputs": { "flake": false,
"nixpkgs": [
"nixCargoIntegration",
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1763606317, "lastModified": 1629857564,
"narHash": "sha256-lsq4Urmb9Iyg2zyg2yG6oMQk9yuaoIgy+jgvYM4guxA=", "narHash": "sha256-dClWiHkbaCDaIl520Miri66UOA8OecWbaVTWJBajHyM=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "a5615abaf30cfaef2e32f1ff9bd5ca94e2911371", "rev": "88848c36934318e16c86097f65dbf97a57968d81",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -224,50 +91,6 @@
"repo": "rust-overlay", "repo": "rust-overlay",
"type": "github" "type": "github"
} }
},
"slimlock": {
"inputs": {
"nixpkgs": [
"nixCargoIntegration",
"dream2nix",
"purescript-overlay",
"nixpkgs"
]
},
"locked": {
"lastModified": 1688756706,
"narHash": "sha256-xzkkMv3neJJJ89zo3o2ojp7nFeaZc2G0fYwNXNJRFlo=",
"owner": "thomashoneyman",
"repo": "slimlock",
"rev": "cf72723f59e2340d24881fd7bf61cb113b4c407c",
"type": "github"
},
"original": {
"owner": "thomashoneyman",
"repo": "slimlock",
"type": "github"
}
},
"treefmt": {
"inputs": {
"nixpkgs": [
"nixCargoIntegration",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762938485,
"narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@@ -11,28 +11,18 @@
}; };
}; };
outputs = inputs: let outputs = inputs:
pkgs = import inputs.nixpkgs { inputs.nixCargoIntegration.lib.makeOutputs {
system = "x86_64-linux"; root = ./.;
overrides = {
shell = common: prev: {
env = prev.env ++ [
{
name = "GST_PLUGIN_PATH";
value = "${common.pkgs.gst_all_1.gstreamer}:${common.pkgs.gst_all_1.gst-plugins-bad}:${common.pkgs.gst_all_1.gst-plugins-ugly}:${common.pkgs.gst_all_1.gst-plugins-good}:${common.pkgs.gst_all_1.gst-plugins-base}";
}
];
};
};
}; };
in {
devShells."x86_64-linux".default = pkgs.mkShell {
# "GST_PLUGIN_PATH" = "${pkgs.gst_all_1.gstreamer}:${pkgs.gst_all_1.gst-plugins-bad}:${pkgs.gst_all_1.gst-plugins-ugly}:${pkgs.gst_all_1.gst-plugins-good}:${pkgs.gst_all_1.gst-plugins-base}";
buildInputs = with pkgs; [
gst_all_1.gstreamer
gst_all_1.gst-plugins-bad
gst_all_1.gst-plugins-ugly
gst_all_1.gst-plugins-good
gst_all_1.gst-plugins-base
libxkbcommon
wayland
rustup
];
nativeBuildInputs = with pkgs; [
pkg-config
wayland
];
packages = with pkgs; [wayland];
};
};
} }

View File

@@ -1,12 +1,12 @@
use crate::video::Frame; use crate::video::Frame;
use iced_wgpu::primitive::Primitive; use iced_wgpu::primitive::{Pipeline, Primitive};
use iced_wgpu::wgpu; use iced_wgpu::wgpu;
use std::{ use std::{
collections::{btree_map::Entry, BTreeMap}, collections::{BTreeMap, btree_map::Entry},
num::NonZero, num::NonZero,
sync::{ sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc, Mutex, Arc, Mutex,
atomic::{AtomicBool, AtomicUsize, Ordering},
}, },
}; };
@@ -35,8 +35,8 @@ pub(crate) struct VideoPipeline {
videos: BTreeMap<u64, VideoEntry>, videos: BTreeMap<u64, VideoEntry>,
} }
impl VideoPipeline { impl Pipeline for VideoPipeline {
fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { fn new(device: &wgpu::Device, _queue: &wgpu::Queue, format: wgpu::TextureFormat) -> Self {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("iced_video_player shader"), label: Some("iced_video_player shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
@@ -97,7 +97,7 @@ impl VideoPipeline {
module: &shader, module: &shader,
entry_point: Some("vs_main"), entry_point: Some("vs_main"),
buffers: &[], buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(), compilation_options: Default::default(),
}, },
primitive: wgpu::PrimitiveState::default(), primitive: wgpu::PrimitiveState::default(),
depth_stencil: None, depth_stencil: None,
@@ -114,7 +114,7 @@ impl VideoPipeline {
blend: None, blend: None,
write_mask: wgpu::ColorWrites::ALL, write_mask: wgpu::ColorWrites::ALL,
})], })],
compilation_options: wgpu::PipelineCompilationOptions::default(), compilation_options: Default::default(),
}), }),
multiview: None, multiview: None,
cache: None, cache: None,
@@ -143,6 +143,23 @@ impl VideoPipeline {
} }
} }
fn trim(&mut self) {
let ids: Vec<_> = self
.videos
.iter()
.filter_map(|(id, entry)| (!entry.alive.load(Ordering::SeqCst)).then_some(*id))
.collect();
for id in ids {
if let Some(video) = self.videos.remove(&id) {
video.texture_y.destroy();
video.texture_uv.destroy();
video.instances.destroy();
}
}
}
}
impl VideoPipeline {
fn upload( fn upload(
&mut self, &mut self,
device: &wgpu::Device, device: &wgpu::Device,
@@ -151,7 +168,10 @@ impl VideoPipeline {
alive: &Arc<AtomicBool>, alive: &Arc<AtomicBool>,
(width, height): (u32, u32), (width, height): (u32, u32),
frame: &[u8], frame: &[u8],
stride: Option<u32>,
) { ) {
// Use stride from GStreamer's VideoMeta if available, otherwise assume stride == width
let stride = stride.unwrap_or(width);
if let Entry::Vacant(entry) = self.videos.entry(video_id) { if let Entry::Vacant(entry) = self.videos.entry(video_id) {
let texture_y = device.create_texture(&wgpu::TextureDescriptor { let texture_y = device.create_texture(&wgpu::TextureDescriptor {
label: Some("iced_video_player texture"), label: Some("iced_video_player texture"),
@@ -192,7 +212,7 @@ impl VideoPipeline {
mip_level_count: None, mip_level_count: None,
base_array_layer: 0, base_array_layer: 0,
array_layer_count: None, array_layer_count: None,
usage: Some(wgpu::TextureUsages::empty()), usage: None,
}); });
let view_uv = texture_uv.create_view(&wgpu::TextureViewDescriptor { let view_uv = texture_uv.create_view(&wgpu::TextureViewDescriptor {
@@ -204,7 +224,7 @@ impl VideoPipeline {
mip_level_count: None, mip_level_count: None,
base_array_layer: 0, base_array_layer: 0,
array_layer_count: None, array_layer_count: None,
usage: Some(wgpu::TextureUsages::empty()), usage: None,
}); });
let instances = device.create_buffer(&wgpu::BufferDescriptor { let instances = device.create_buffer(&wgpu::BufferDescriptor {
@@ -266,10 +286,10 @@ impl VideoPipeline {
origin: wgpu::Origin3d::ZERO, origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All, aspect: wgpu::TextureAspect::All,
}, },
&frame[..(width * height) as usize], &frame[..(stride * height) as usize],
wgpu::TexelCopyBufferLayout { wgpu::TexelCopyBufferLayout {
offset: 0, offset: 0,
bytes_per_row: Some(width), bytes_per_row: Some(stride),
rows_per_image: Some(height), rows_per_image: Some(height),
}, },
wgpu::Extent3d { wgpu::Extent3d {
@@ -286,10 +306,10 @@ impl VideoPipeline {
origin: wgpu::Origin3d::ZERO, origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All, aspect: wgpu::TextureAspect::All,
}, },
&frame[(width * height) as usize..], &frame[(stride * height) as usize..],
wgpu::TexelCopyBufferLayout { wgpu::TexelCopyBufferLayout {
offset: 0, offset: 0,
bytes_per_row: Some(width), bytes_per_row: Some(stride),
rows_per_image: Some(height / 2), rows_per_image: Some(height / 2),
}, },
wgpu::Extent3d { wgpu::Extent3d {
@@ -300,21 +320,6 @@ impl VideoPipeline {
); );
} }
fn cleanup(&mut self) {
let ids: Vec<_> = self
.videos
.iter()
.filter_map(|(id, entry)| (!entry.alive.load(Ordering::SeqCst)).then_some(*id))
.collect();
for id in ids {
if let Some(video) = self.videos.remove(&id) {
video.texture_y.destroy();
video.texture_uv.destroy();
video.instances.destroy();
}
}
}
fn prepare(&mut self, queue: &wgpu::Queue, video_id: u64, bounds: &iced::Rectangle) { fn prepare(&mut self, queue: &wgpu::Queue, video_id: u64, bounds: &iced::Rectangle) {
if let Some(video) = self.videos.get_mut(&video_id) { if let Some(video) = self.videos.get_mut(&video_id) {
let uniforms = Uniforms { let uniforms = Uniforms {
@@ -340,8 +345,6 @@ impl VideoPipeline {
video.prepare_index.fetch_add(1, Ordering::Relaxed); video.prepare_index.fetch_add(1, Ordering::Relaxed);
video.render_index.store(0, Ordering::Relaxed); video.render_index.store(0, Ordering::Relaxed);
} }
self.cleanup();
} }
fn draw( fn draw(
@@ -414,39 +417,33 @@ impl VideoPrimitive {
} }
impl Primitive for VideoPrimitive { impl Primitive for VideoPrimitive {
type Renderer = VideoPipeline; type Pipeline = VideoPipeline;
fn initialize(
&self,
device: &wgpu::Device,
_queue: &wgpu::Queue,
format: wgpu::TextureFormat,
) -> Self::Renderer {
VideoPipeline::new(device, format)
}
fn prepare( fn prepare(
&self, &self,
renderer: &mut Self::Renderer, pipeline: &mut VideoPipeline,
device: &wgpu::Device, device: &wgpu::Device,
queue: &wgpu::Queue, queue: &wgpu::Queue,
bounds: &iced::Rectangle, bounds: &iced::Rectangle,
viewport: &iced_wgpu::graphics::Viewport, viewport: &iced_wgpu::graphics::Viewport,
) { ) {
if self.upload_frame { if self.upload_frame {
if let Some(readable) = self.frame.lock().expect("lock frame mutex").readable() { let frame_guard = self.frame.lock().expect("lock frame mutex");
renderer.upload( let stride = frame_guard.stride();
if let Some(readable) = frame_guard.readable() {
pipeline.upload(
device, device,
queue, queue,
self.video_id, self.video_id,
&self.alive, &self.alive,
self.size, self.size,
readable.as_slice(), readable.as_slice(),
stride,
); );
} };
} }
renderer.prepare( pipeline.prepare(
queue, queue,
self.video_id, self.video_id,
&(*bounds &(*bounds
@@ -459,11 +456,11 @@ impl Primitive for VideoPrimitive {
fn render( fn render(
&self, &self,
renderer: &Self::Renderer, pipeline: &Self::Pipeline,
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
target: &wgpu::TextureView, target: &wgpu::TextureView,
clip_bounds: &iced::Rectangle<u32>, clip_bounds: &iced::Rectangle<u32>,
) { ) {
renderer.draw(target, encoder, clip_bounds, self.video_id); pipeline.draw(target, encoder, clip_bounds, self.video_id);
} }
} }

View File

@@ -38,24 +38,19 @@ fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> VertexOutput {
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let yuv2r = vec3<f32>(1.164, 0.0, 1.596); // BT.709 precomputed coefficents
let yuv2g = vec3<f32>(1.164, -0.391, -0.813); let yuv2rgb = mat3x3<f32>(
let yuv2b = vec3<f32>(1.164, 2.018, 0.0); 1, 0, 1.5748,
1, -0.1873, -0.4681,
1, 1.8556, 0,
);
var yuv = vec3<f32>(0.0); var yuv = vec3<f32>(0.0);
yuv.x = textureSample(tex_y, s, in.uv).r - 0.0625; yuv.x = (textureSample(tex_y, s, in.uv).r - 0.0625) / 0.8588;
yuv.y = textureSample(tex_uv, s, in.uv).r - 0.5; yuv.y = (textureSample(tex_uv, s, in.uv).r - 0.5) / 0.8784;
yuv.z = textureSample(tex_uv, s, in.uv).g - 0.5; yuv.z = (textureSample(tex_uv, s, in.uv).g - 0.5) / 0.8784;
var rgb = vec3<f32>(0.0); var rgb = clamp(yuv * yuv2rgb, vec3<f32>(0), vec3<f32>(1));
rgb.x = dot(yuv, yuv2r);
rgb.y = dot(yuv, yuv2g);
rgb.z = dot(yuv, yuv2b);
let threshold = rgb <= vec3<f32>(0.04045);
let hi = pow((rgb + vec3<f32>(0.055)) / vec3<f32>(1.055), vec3<f32>(2.4));
let lo = rgb * vec3<f32>(1.0 / 12.92);
rgb = select(hi, lo, threshold);
return vec4<f32>(rgb, 1.0); return vec4<f32>(rgb, 1.0);
} }

View File

@@ -2,6 +2,7 @@ use crate::Error;
use gstreamer as gst; use gstreamer as gst;
use gstreamer_app as gst_app; use gstreamer_app as gst_app;
use gstreamer_app::prelude::*; use gstreamer_app::prelude::*;
use gstreamer_video::VideoMeta;
use iced::widget::image as img; use iced::widget::image as img;
use std::num::NonZeroU8; use std::num::NonZeroU8;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@@ -49,9 +50,19 @@ impl Frame {
Self(gst::Sample::builder().build()) Self(gst::Sample::builder().build())
} }
pub fn readable(&self) -> Option<gst::BufferMap<'_, gst::buffer::Readable>> { pub fn readable(&self) -> Option<gst::BufferMap<gst::buffer::Readable>> {
self.0.buffer().and_then(|x| x.map_readable().ok()) self.0.buffer().and_then(|x| x.map_readable().ok())
} }
/// Get the Y-plane stride (line pitch) in bytes from the frame's VideoMeta.
/// This is critical for proper NV12 decoding, as the stride may differ from width.
pub fn stride(&self) -> Option<u32> {
self.0.buffer().and_then(|buffer| {
buffer
.meta::<VideoMeta>()
.map(|meta| meta.stride()[0] as u32)
})
}
} }
#[derive(Debug)] #[derive(Debug)]
@@ -284,8 +295,6 @@ impl Video {
let s = cleanup!(caps.structure(0).ok_or(Error::Caps))?; let s = cleanup!(caps.structure(0).ok_or(Error::Caps))?;
let width = cleanup!(s.get::<i32>("width").map_err(|_| Error::Caps))?; let width = cleanup!(s.get::<i32>("width").map_err(|_| Error::Caps))?;
let height = cleanup!(s.get::<i32>("height").map_err(|_| Error::Caps))?; let height = cleanup!(s.get::<i32>("height").map_err(|_| Error::Caps))?;
// resolution should be mod4
let width = ((width + 4 - 1) / 4) * 4;
let framerate = cleanup!(s.get::<gst::Fraction>("framerate").map_err(|_| Error::Caps))?; let framerate = cleanup!(s.get::<gst::Fraction>("framerate").map_err(|_| Error::Caps))?;
let framerate = framerate.numer() as f64 / framerate.denom() as f64; let framerate = framerate.numer() as f64 / framerate.denom() as f64;
@@ -305,7 +314,7 @@ impl Video {
.unwrap_or(0), .unwrap_or(0),
); );
let sync_av = pipeline.has_property("av-offset"); let sync_av = pipeline.has_property("av-offset", None);
// NV12 = 12bpp // NV12 = 12bpp
let frame = Arc::new(Mutex::new(Frame::empty())); let frame = Arc::new(Mutex::new(Frame::empty()));
@@ -612,11 +621,12 @@ impl Video {
} }
let frame_guard = inner.frame.lock().map_err(|_| Error::Lock)?; let frame_guard = inner.frame.lock().map_err(|_| Error::Lock)?;
let frame = frame_guard.readable().ok_or(Error::Lock)?; let frame = frame_guard.readable().ok_or(Error::Lock)?;
let stride = frame_guard.stride();
Ok(img::Handle::from_rgba( Ok(img::Handle::from_rgba(
inner.width as u32 / downscale, inner.width as u32 / downscale,
inner.height as u32 / downscale, inner.height as u32 / downscale,
yuv_to_rgba(frame.as_slice(), width as _, height as _, downscale), yuv_to_rgba(frame.as_slice(), width as _, height as _, downscale, stride),
)) ))
}) })
.collect() .collect()
@@ -630,8 +640,17 @@ impl Video {
} }
} }
fn yuv_to_rgba(yuv: &[u8], width: u32, height: u32, downscale: u32) -> Vec<u8> { fn yuv_to_rgba(
let uv_start = width * height; yuv: &[u8],
width: u32,
height: u32,
downscale: u32,
stride: Option<u32>,
) -> Vec<u8> {
// Use stride from VideoMeta if available, otherwise assume stride == width
let stride = stride.unwrap_or(width);
let uv_start = stride * height;
let mut rgba = vec![]; let mut rgba = vec![];
for y in 0..height / downscale { for y in 0..height / downscale {
@@ -639,11 +658,16 @@ fn yuv_to_rgba(yuv: &[u8], width: u32, height: u32, downscale: u32) -> Vec<u8> {
let x_src = x * downscale; let x_src = x * downscale;
let y_src = y * downscale; let y_src = y * downscale;
let uv_i = uv_start + width * (y_src / 2) + x_src / 2 * 2; // NV12 memory layout with stride:
// Y plane: stride bytes per row, starting at offset 0
// UV plane: stride bytes per row (same stride), starting at offset stride * height
// Each pixel is 1 byte Y, and every 2x2 block shares 2 bytes (U, V)
let y_offset = (y_src * stride + x_src) as usize;
let uv_offset = (uv_start + (y_src / 2) * stride + (x_src / 2) * 2) as usize;
let y = yuv[(y_src * width + x_src) as usize] as f32; let y = yuv[y_offset] as f32;
let u = yuv[uv_i as usize] as f32; let u = yuv[uv_offset] as f32;
let v = yuv[(uv_i + 1) as usize] as f32; let v = yuv[uv_offset + 1] as f32;
let r = 1.164 * (y - 16.0) + 1.596 * (v - 128.0); let r = 1.164 * (y - 16.0) + 1.596 * (v - 128.0);
let g = 1.164 * (y - 16.0) - 0.813 * (v - 128.0) - 0.391 * (u - 128.0); let g = 1.164 * (y - 16.0) - 0.813 * (v - 128.0) - 0.391 * (u - 128.0);

View File

@@ -1,12 +1,12 @@
use crate::{pipeline::VideoPrimitive, video::Video}; use crate::{pipeline::VideoPrimitive, video::Video};
use gstreamer as gst; use gstreamer as gst;
use iced::{ use iced::{
advanced::{self, layout, widget, Widget},
Element, Element,
advanced::{self, Widget, layout, widget},
}; };
use iced_wgpu::primitive::Renderer as PrimitiveRenderer; use iced_wgpu::primitive::Renderer as PrimitiveRenderer;
use log::error; use log::error;
use std::{marker::PhantomData, sync::atomic::Ordering}; use std::{marker::PhantomData, sync::atomic::Ordering, time::Duration};
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
/// Video player widget which displays the current frame of a [`Video`](crate::Video). /// Video player widget which displays the current frame of a [`Video`](crate::Video).
@@ -214,7 +214,7 @@ where
fn update( fn update(
&mut self, &mut self,
_state: &mut widget::Tree, _tree: &mut widget::Tree,
event: &iced::Event, event: &iced::Event,
_layout: advanced::Layout<'_>, _layout: advanced::Layout<'_>,
_cursor: advanced::mouse::Cursor, _cursor: advanced::mouse::Cursor,
@@ -228,6 +228,7 @@ where
if let iced::Event::Window(iced::window::Event::RedrawRequested(_)) = event { if let iced::Event::Window(iced::window::Event::RedrawRequested(_)) = event {
if inner.restart_stream || (!inner.is_eos && !inner.paused()) { if inner.restart_stream || (!inner.is_eos && !inner.paused()) {
let mut restart_stream = false; let mut restart_stream = false;
let emit_eos = !inner.restart_stream;
if inner.restart_stream { if inner.restart_stream {
restart_stream = true; restart_stream = true;
// Set flag to false to avoid potentially multiple seeks // Set flag to false to avoid potentially multiple seeks
@@ -247,7 +248,9 @@ where
}; };
} }
gst::MessageView::Eos(_eos) => { gst::MessageView::Eos(_eos) => {
if let Some(on_end_of_stream) = self.on_end_of_stream.clone() { if emit_eos
&& let Some(on_end_of_stream) = self.on_end_of_stream.clone()
{
shell.publish(on_end_of_stream); shell.publish(on_end_of_stream);
} }
if inner.looping { if inner.looping {
@@ -285,8 +288,11 @@ where
} }
shell.request_redraw(); shell.request_redraw();
shell.capture_event();
} else { } else {
shell.request_redraw(); shell.request_redraw_at(iced::window::RedrawRequest::At(
Instant::now() + Duration::from_millis(32),
));
} }
} }
} }

View File

@@ -3,4 +3,7 @@ typegen:
cd typegen && cargo run cd typegen && cargo run
cp typegen/jellyfin.rs api/src/jellyfin.rs cp typegen/jellyfin.rs api/src/jellyfin.rs
rm typegen/jellyfin.rs rm typegen/jellyfin.rs
playbin:
gst-launch-1.0 playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm text-sink="appsink name=iced_text sync=true drop=true" video-sink="videoscale ! videoconvert ! appsink name=iced_video drop=true caps=video/x-raw,format=NV12,pixel-aspect-ratio=1/1"

View File

@@ -8,6 +8,8 @@ fn main() -> Result<()> {
let args = <cli::Cli as clap::Parser>::parse(); let args = <cli::Cli as clap::Parser>::parse();
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_max_level(args.verbosity) .with_max_level(args.verbosity)
.with_file(true)
.with_line_number(true)
.init(); .init();
ui_iced::ui().change_context(Error)?; ui_iced::ui().change_context(Error)?;
Ok(()) Ok(())

View File

@@ -1,4 +1,3 @@
use std::{ use std::{
borrow::Borrow, borrow::Borrow,
collections::VecDeque, collections::VecDeque,

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -17,16 +17,24 @@ pub fn update(state: &mut State, message: VideoMessage) -> Task<Message> {
Task::none() Task::none()
} }
VideoMessage::Open(url) => { VideoMessage::Open(url) => {
state.video = Video::new(&url) match Video::new(&url)
.inspect_err(|err| { .inspect_err(|err| {
tracing::error!("Failed to play video at {}: {:?}", url, err); tracing::error!("Failed to play video at {}: {:?}", url, err);
}) })
.inspect(|video| { .inspect(|video| {
tracing::info!("Framerate {}", video.framerate()); tracing::error!("Framerate is {}", video.framerate());
}) })
.ok() .map(Arc::new)
.map(Arc::new); {
Task::none() Ok(video) => {
state.video = Some(video);
Task::none()
}
Err(err) => Task::done(Message::Error(format!(
"Error opening video at {}: {:?}",
url, err
))),
}
} }
VideoMessage::Pause => { VideoMessage::Pause => {
if let Some(video) = state.video.as_mut().and_then(Arc::get_mut) { if let Some(video) = state.video.as_mut().and_then(Arc::get_mut) {
@@ -56,14 +64,8 @@ pub fn update(state: &mut State, message: VideoMessage) -> Task<Message> {
"https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm",
// "https://www.youtube.com/watch?v=QbUUaXGA3C4", // "https://www.youtube.com/watch?v=QbUUaXGA3C4",
) )
.unwrap(); .expect("Impossible: Failed to parse hardcoded URL");
state.video = Video::new(&url) Task::done(Message::Video(VideoMessage::Open(url)))
.inspect_err(|err| {
tracing::error!("{err:?}");
})
.ok()
.map(Arc::new);
Task::none()
} }
} }
} }