Merge pull request #3336 from fufesou/feat/texture2

feat/texture use flutter texture for render
This commit is contained in:
RustDesk 2023-02-23 18:55:42 +08:00 committed by GitHub
commit cacbc60c11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 798 additions and 275 deletions

View File

@ -593,7 +593,7 @@ jobs:
x86_64) x86_64)
# no need mock on x86_64 # no need mock on x86_64
export VCPKG_ROOT=/opt/artifacts/vcpkg export VCPKG_ROOT=/opt/artifacts/vcpkg
cargo build --lib --features hwcodec,flutter,${{ matrix.job.extra-build-features }} --release cargo build --lib --features hwcodec,flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
;; ;;
esac esac
@ -761,7 +761,7 @@ jobs:
ln -s /usr/include /vcpkg/installed/arm64-linux/include ln -s /usr/include /vcpkg/installed/arm64-linux/include
export VCPKG_ROOT=/vcpkg export VCPKG_ROOT=/vcpkg
# disable hwcodec for compilation # disable hwcodec for compilation
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
;; ;;
armv7) armv7)
cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/ cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/
@ -771,7 +771,7 @@ jobs:
ln -s /usr/include /vcpkg/installed/arm-linux/include ln -s /usr/include /vcpkg/installed/arm-linux/include
export VCPKG_ROOT=/vcpkg export VCPKG_ROOT=/vcpkg
# disable hwcodec for compilation # disable hwcodec for compilation
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
;; ;;
esac esac

View File

@ -732,7 +732,7 @@ jobs:
x86_64) x86_64)
# no need mock on x86_64 # no need mock on x86_64
export VCPKG_ROOT=/opt/artifacts/vcpkg export VCPKG_ROOT=/opt/artifacts/vcpkg
cargo build --lib --features hwcodec,flutter,${{ matrix.job.extra-build-features }} --release cargo build --lib --features hwcodec,flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
;; ;;
esac esac
@ -900,7 +900,7 @@ jobs:
ln -s /usr/include /vcpkg/installed/arm64-linux/include ln -s /usr/include /vcpkg/installed/arm64-linux/include
export VCPKG_ROOT=/vcpkg export VCPKG_ROOT=/vcpkg
# disable hwcodec for compilation # disable hwcodec for compilation
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
;; ;;
armv7) armv7)
cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/ cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/
@ -910,7 +910,7 @@ jobs:
ln -s /usr/include /vcpkg/installed/arm-linux/include ln -s /usr/include /vcpkg/installed/arm-linux/include
export VCPKG_ROOT=/vcpkg export VCPKG_ROOT=/vcpkg
# disable hwcodec for compilation # disable hwcodec for compilation
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
;; ;;
esac esac

327
Cargo.lock generated
View File

@ -254,9 +254,9 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -271,9 +271,9 @@ version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -377,8 +377,8 @@ dependencies = [
"lazycell", "lazycell",
"log", "log",
"peeking_take_while", "peeking_take_while",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
@ -397,12 +397,12 @@ dependencies = [
"lazy_static", "lazy_static",
"lazycell", "lazycell",
"peeking_take_while", "peeking_take_while",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -588,11 +588,11 @@ dependencies = [
"heck 0.4.0", "heck 0.4.0",
"indexmap", "indexmap",
"log", "log",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"serde 1.0.149", "serde 1.0.149",
"serde_json 1.0.89", "serde_json 1.0.89",
"syn", "syn 1.0.105",
"tempfile", "tempfile",
"toml", "toml",
] ]
@ -721,9 +721,9 @@ checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [ dependencies = [
"heck 0.4.0", "heck 0.4.0",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1119,10 +1119,10 @@ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"scratch", "scratch",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1137,9 +1137,9 @@ version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1177,10 +1177,10 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"strsim 0.10.0", "strsim 0.10.0",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1190,8 +1190,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1373,9 +1373,9 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "082a24a9967533dc5d743c602157637116fc1b52806d694a5a45e6f32567fcdd" checksum = "082a24a9967533dc5d743c602157637116fc1b52806d694a5a45e6f32567fcdd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1384,9 +1384,9 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1481,6 +1481,29 @@ dependencies = [
"libloading", "libloading",
] ]
[[package]]
name = "dlopen"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937"
dependencies = [
"dlopen_derive",
"lazy_static",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "dlopen_derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581"
dependencies = [
"libc",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]] [[package]]
name = "dlv-list" name = "dlv-list"
version = "0.3.0" version = "0.3.0"
@ -1592,9 +1615,9 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9045e2676cd5af83c3b167d917b0a5c90a4d8e266e2683d6631b235c457fc27" checksum = "a9045e2676cd5af83c3b167d917b0a5c90a4d8e266e2683d6631b235c457fc27"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1604,9 +1627,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eb359f1476bf611266ac1f5355bc14aeca37b299d0ebccc038ee7058891c9cb" checksum = "0eb359f1476bf611266ac1f5355bc14aeca37b299d0ebccc038ee7058891c9cb"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1625,9 +1648,9 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1670,10 +1693,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e" checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"rustversion", "rustversion",
"syn", "syn 1.0.105",
"synstructure", "synstructure",
] ]
@ -1747,9 +1770,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610" checksum = "5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -1878,11 +1901,11 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"pathdiff", "pathdiff",
"quote", "quote 1.0.21",
"regex", "regex",
"serde 1.0.149", "serde 1.0.149",
"serde_yaml", "serde_yaml",
"syn", "syn 1.0.105",
"tempfile", "tempfile",
"thiserror", "thiserror",
"toml", "toml",
@ -2035,9 +2058,9 @@ version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -2299,9 +2322,9 @@ dependencies = [
"itertools 0.9.0", "itertools 0.9.0",
"proc-macro-crate 0.1.5", "proc-macro-crate 0.1.5",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -2314,9 +2337,9 @@ dependencies = [
"heck 0.4.0", "heck 0.4.0",
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -2550,9 +2573,9 @@ dependencies = [
"anyhow", "anyhow",
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -2856,8 +2879,8 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
] ]
[[package]] [[package]]
@ -3564,9 +3587,9 @@ checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -3713,9 +3736,9 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -3805,9 +3828,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [ dependencies = [
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -4121,9 +4144,9 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -4230,9 +4253,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
"version_check", "version_check",
] ]
@ -4242,11 +4265,20 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"version_check", "version_check",
] ]
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid 0.1.0",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.47" version = "1.0.47"
@ -4374,13 +4406,22 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2 0.4.30",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
] ]
[[package]] [[package]]
@ -4846,6 +4887,7 @@ dependencies = [
"dbus-crossroads", "dbus-crossroads",
"default-net", "default-net",
"dispatch", "dispatch",
"dlopen",
"enigo", "enigo",
"errno", "errno",
"evdev", "evdev",
@ -5157,9 +5199,9 @@ version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -5191,9 +5233,9 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -5452,9 +5494,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
dependencies = [ dependencies = [
"heck 0.3.3", "heck 0.3.3",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -5464,10 +5506,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [ dependencies = [
"heck 0.4.0", "heck 0.4.0",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"rustversion", "rustversion",
"syn", "syn 1.0.105",
]
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"unicode-xid 0.1.0",
] ]
[[package]] [[package]]
@ -5476,8 +5529,8 @@ version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"unicode-ident", "unicode-ident",
] ]
@ -5487,10 +5540,10 @@ version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
"unicode-xid", "unicode-xid 0.2.4",
] ]
[[package]] [[package]]
@ -5629,9 +5682,9 @@ name = "tao-macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/tauri-apps/tao?branch=muda#676bd90a80286b893d8850cc4e3813a0c4a27dcf" source = "git+https://github.com/tauri-apps/tao?branch=muda#676bd90a80286b893d8850cc4e3813a0c4a27dcf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -5724,9 +5777,9 @@ version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -5830,9 +5883,9 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -5919,9 +5972,9 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -6032,6 +6085,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.4" version = "0.2.4"
@ -6176,9 +6235,9 @@ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6200,7 +6259,7 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [ dependencies = [
"quote", "quote 1.0.21",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
] ]
@ -6210,9 +6269,9 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6280,8 +6339,8 @@ version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"xml-rs", "xml-rs",
] ]
@ -6506,9 +6565,9 @@ version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6" checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -6517,9 +6576,9 @@ version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f" checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -6961,10 +7020,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45066039ebf3330820e495e854f8b312abb68f0a39e97972d092bd72e8bb3e8e" checksum = "45066039ebf3330820e495e854f8b312abb68f0a39e97972d092bd72e8bb3e8e"
dependencies = [ dependencies = [
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"regex", "regex",
"syn", "syn 1.0.105",
] ]
[[package]] [[package]]
@ -7037,7 +7096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "155247a5d1ab55e335421c104ccd95d64f17cebbd02f50cdbc1c33385f9c4d81" checksum = "155247a5d1ab55e335421c104ccd95d64f17cebbd02f50cdbc1c33385f9c4d81"
dependencies = [ dependencies = [
"proc-macro-crate 1.2.1", "proc-macro-crate 1.2.1",
"proc-macro2", "proc-macro2 1.0.47",
"quote", "quote 1.0.21",
"syn", "syn 1.0.105",
] ]

View File

@ -20,6 +20,7 @@ inline = []
hbbs = [] hbbs = []
cli = [] cli = []
with_rc = ["simple_rc"] with_rc = ["simple_rc"]
flutter_texture_render = []
appimage = [] appimage = []
flatpak = [] flatpak = []
use_samplerate = ["samplerate"] use_samplerate = ["samplerate"]
@ -63,6 +64,7 @@ flutter_rust_bridge = { version = "1.61.1", optional = true }
errno = "0.2.8" errno = "0.2.8"
rdev = { git = "https://github.com/fufesou/rdev" } rdev = { git = "https://github.com/fufesou/rdev" }
url = { version = "2.1", features = ["serde"] } url = { version = "2.1", features = ["serde"] }
dlopen = "0.1"
reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false }
chrono = "0.4.23" chrono = "0.4.23"

View File

@ -239,6 +239,7 @@ def get_features(args):
features.append('hwcodec') features.append('hwcodec')
if args.flutter: if args.flutter:
features.append('flutter') features.append('flutter')
features.append('flutter_texture_render')
if args.flatpak: if args.flatpak:
features.append('flatpak') features.append('flatpak')
if args.appimage: if args.appimage:

View File

@ -19,6 +19,7 @@ import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:flutter_hbb/utils/platform_channel.dart'; import 'package:flutter_hbb/utils/platform_channel.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:uni_links_desktop/uni_links_desktop.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -44,6 +45,10 @@ var isWeb = false;
var isWebDesktop = false; var isWebDesktop = false;
var version = ""; var version = "";
int androidVersion = 0; int androidVersion = 0;
/// Incriment count for textureId.
int _textureId = 0;
int get newTextureId => _textureId ++;
final textureRenderer = TextureRgbaRenderer();
/// only available for Windows target /// only available for Windows target
int windowsBuildNumber = 0; int windowsBuildNumber = 0;

View File

@ -63,6 +63,9 @@ class _RemotePageState extends State<RemotePage>
late RxBool _zoomCursor; late RxBool _zoomCursor;
late RxBool _remoteCursorMoved; late RxBool _remoteCursorMoved;
late RxBool _keyboardEnabled; late RxBool _keyboardEnabled;
late RxInt _textureId;
late int _textureKey;
final useTextureRender = bind.mainUseTextureRender();
final _blockableOverlayState = BlockableOverlayState(); final _blockableOverlayState = BlockableOverlayState();
@ -85,6 +88,8 @@ class _RemotePageState extends State<RemotePage>
_showRemoteCursor = ShowRemoteCursorState.find(id); _showRemoteCursor = ShowRemoteCursorState.find(id);
_keyboardEnabled = KeyboardEnabledState.find(id); _keyboardEnabled = KeyboardEnabledState.find(id);
_remoteCursorMoved = RemoteCursorMovedState.find(id); _remoteCursorMoved = RemoteCursorMovedState.find(id);
_textureKey = newTextureId;
_textureId = RxInt(-1);
} }
void _removeStates(String id) { void _removeStates(String id) {
@ -119,6 +124,18 @@ class _RemotePageState extends State<RemotePage>
if (!Platform.isLinux) { if (!Platform.isLinux) {
Wakelock.enable(); Wakelock.enable();
} }
// Register texture.
_textureId.value = -1;
if (useTextureRender) {
textureRenderer.createTexture(_textureKey).then((id) async {
debugPrint("id: $id, texture_key: $_textureKey");
if (id != -1) {
final ptr = await textureRenderer.getTexturePtr(_textureKey);
platformFFI.registerTexture(widget.id, ptr);
_textureId.value = id;
}
});
}
_ffi.ffiModel.updateEventListener(widget.id); _ffi.ffiModel.updateEventListener(widget.id);
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
// Session option should be set after models.dart/FFI.start // Session option should be set after models.dart/FFI.start
@ -183,6 +200,10 @@ class _RemotePageState extends State<RemotePage>
@override @override
void dispose() { void dispose() {
debugPrint("REMOTE PAGE dispose ${widget.id}"); debugPrint("REMOTE PAGE dispose ${widget.id}");
if (useTextureRender) {
platformFFI.registerTexture(widget.id, 0);
textureRenderer.closeTexture(_textureKey);
}
// ensure we leave this session, this is a double check // ensure we leave this session, this is a double check
bind.sessionEnterOrLeave(id: widget.id, enter: false); bind.sessionEnterOrLeave(id: widget.id, enter: false);
DesktopMultiWindow.removeListener(this); DesktopMultiWindow.removeListener(this);
@ -346,6 +367,8 @@ class _RemotePageState extends State<RemotePage>
cursorOverImage: _cursorOverImage, cursorOverImage: _cursorOverImage,
keyboardEnabled: _keyboardEnabled, keyboardEnabled: _keyboardEnabled,
remoteCursorMoved: _remoteCursorMoved, remoteCursorMoved: _remoteCursorMoved,
textureId: _textureId,
useTextureRender: useTextureRender,
listenerBuilder: (child) => listenerBuilder: (child) =>
_buildRawPointerMouseRegion(child, enterView, leaveView), _buildRawPointerMouseRegion(child, enterView, leaveView),
); );
@ -383,6 +406,8 @@ class ImagePaint extends StatefulWidget {
final RxBool cursorOverImage; final RxBool cursorOverImage;
final RxBool keyboardEnabled; final RxBool keyboardEnabled;
final RxBool remoteCursorMoved; final RxBool remoteCursorMoved;
final RxInt textureId;
final bool useTextureRender;
final Widget Function(Widget)? listenerBuilder; final Widget Function(Widget)? listenerBuilder;
ImagePaint( ImagePaint(
@ -392,6 +417,8 @@ class ImagePaint extends StatefulWidget {
required this.cursorOverImage, required this.cursorOverImage,
required this.keyboardEnabled, required this.keyboardEnabled,
required this.remoteCursorMoved, required this.remoteCursorMoved,
required this.textureId,
required this.useTextureRender,
this.listenerBuilder}) this.listenerBuilder})
: super(key: key); : super(key: key);
@ -466,10 +493,19 @@ class _ImagePaintState extends State<ImagePaint> {
final imageWidth = c.getDisplayWidth() * s; final imageWidth = c.getDisplayWidth() * s;
final imageHeight = c.getDisplayHeight() * s; final imageHeight = c.getDisplayHeight() * s;
final imageSize = Size(imageWidth, imageHeight); final imageSize = Size(imageWidth, imageHeight);
final imageWidget = CustomPaint( late final Widget imageWidget;
size: imageSize, if (widget.useTextureRender) {
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s), imageWidget = SizedBox(
); width: imageWidth,
height: imageHeight,
child: Obx(() => Texture(textureId: widget.textureId.value)),
);
} else {
imageWidget = CustomPaint(
size: imageSize,
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
);
}
return NotificationListener<ScrollNotification>( return NotificationListener<ScrollNotification>(
onNotification: (notification) { onNotification: (notification) {
@ -493,11 +529,31 @@ class _ImagePaintState extends State<ImagePaint> {
context, _buildListener(imageWidget), c.size, imageSize)), context, _buildListener(imageWidget), c.size, imageSize)),
)); ));
} else { } else {
final imageWidget = CustomPaint( late final Widget imageWidget;
size: Size(c.size.width, c.size.height), if (c.size.width > 0 && c.size.height > 0) {
painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), if (widget.useTextureRender) {
); imageWidget = Stack(
return mouseRegion(child: _buildListener(imageWidget)); children: [
Positioned(
left: c.x,
top: c.y,
width: c.getDisplayWidth() * s,
height: c.getDisplayHeight() * s,
child: Texture(textureId: widget.textureId.value),
)
],
);
} else {
imageWidget = CustomPaint(
size: Size(c.size.width, c.size.height),
painter:
ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s),
);
}
return mouseRegion(child: _buildListener(imageWidget));
} else {
return Container();
}
} }
} }

View File

@ -252,6 +252,8 @@ class FfiModel with ChangeNotifier {
parent.target?.cursorModel.updateDisplayOrigin(_display.x, _display.y); parent.target?.cursorModel.updateDisplayOrigin(_display.x, _display.y);
} }
_updateSessionWidthHeight(peerId, display.width, display.height);
try { try {
CurrentDisplayState.find(peerId).value = _pi.currentDisplay; CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
} catch (e) { } catch (e) {
@ -367,6 +369,10 @@ class FfiModel with ChangeNotifier {
}); });
} }
_updateSessionWidthHeight(String id, int width, int height) {
bind.sessionSetSize(id: id, width: display.width, height: display.height);
}
/// Handle the peer info event based on [evt]. /// Handle the peer info event based on [evt].
handlePeerInfo(Map<String, dynamic> evt, String peerId) async { handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
// recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs) // recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs)
@ -420,6 +426,7 @@ class FfiModel with ChangeNotifier {
stateGlobal.displaysCount.value = _pi.displays.length; stateGlobal.displaysCount.value = _pi.displays.length;
if (_pi.currentDisplay < _pi.displays.length) { if (_pi.currentDisplay < _pi.displays.length) {
_display = _pi.displays[_pi.currentDisplay]; _display = _pi.displays[_pi.currentDisplay];
_updateSessionWidthHeight(peerId, display.width, display.height);
} }
if (displays.isNotEmpty) { if (displays.isNotEmpty) {
parent.target?.dialogManager.showLoading( parent.target?.dialogManager.showLoading(
@ -485,19 +492,18 @@ class ImageModel with ChangeNotifier {
WeakReference<FFI> parent; WeakReference<FFI> parent;
final List<Function(String)> _callbacksOnFirstImage = []; final List<Function(String)> callbacksOnFirstImage = [];
ImageModel(this.parent); ImageModel(this.parent);
addCallbackOnFirstImage(Function(String) cb) => addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
_callbacksOnFirstImage.add(cb);
onRgba(Uint8List rgba) { onRgba(Uint8List rgba) {
if (_waitForImage[id]!) { if (_waitForImage[id]!) {
_waitForImage[id] = false; _waitForImage[id] = false;
parent.target?.dialogManager.dismissAll(); parent.target?.dialogManager.dismissAll();
if (isDesktop) { if (isDesktop) {
for (final cb in _callbacksOnFirstImage) { for (final cb in callbacksOnFirstImage) {
cb(id); cb(id);
} }
} }
@ -1432,6 +1438,7 @@ class FFI {
final stream = bind.sessionStart(id: id); final stream = bind.sessionStart(id: id);
final cb = ffiModel.startEventListener(id); final cb = ffiModel.startEventListener(id);
() async { () async {
final useTextureRender = bind.mainUseTextureRender();
// Preserved for the rgba data. // Preserved for the rgba data.
await for (final message in stream) { await for (final message in stream) {
if (message is EventToUI_Event) { if (message is EventToUI_Event) {
@ -1445,14 +1452,26 @@ class FFI {
debugPrint('json.decode fail1(): $e, ${message.field0}'); debugPrint('json.decode fail1(): $e, ${message.field0}');
} }
} else if (message is EventToUI_Rgba) { } else if (message is EventToUI_Rgba) {
// Fetch the image buffer from rust codes. if (useTextureRender) {
final sz = platformFFI.getRgbaSize(id); if (_waitForImage[id]!) {
if (sz == null || sz == 0) { _waitForImage[id] = false;
return; dialogManager.dismissAll();
} for (final cb in imageModel.callbacksOnFirstImage) {
final rgba = platformFFI.getRgba(id, sz); cb(id);
if (rgba != null) { }
imageModel.onRgba(rgba); await canvasModel.updateViewStyle();
await canvasModel.updateScrollStyle();
}
} else {
// Fetch the image buffer from rust codes.
final sz = platformFFI.getRgbaSize(id);
if (sz == null || sz == 0) {
return;
}
final rgba = platformFFI.getRgba(id, sz);
if (rgba != null) {
imageModel.onRgba(rgba);
}
} }
} }
} }

View File

@ -30,6 +30,9 @@ typedef F4Dart = int Function(Pointer<Utf8>);
typedef F5 = Void Function(Pointer<Utf8>); typedef F5 = Void Function(Pointer<Utf8>);
typedef F5Dart = void Function(Pointer<Utf8>); typedef F5Dart = void Function(Pointer<Utf8>);
typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt); typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
// pub fn session_register_texture(id: *const char, ptr: usize)
typedef F6 = Void Function(Pointer<Utf8>, Uint64);
typedef F6Dart = void Function(Pointer<Utf8>, int);
/// FFI wrapper around the native Rust core. /// FFI wrapper around the native Rust core.
/// Hides the platform differences. /// Hides the platform differences.
@ -52,6 +55,8 @@ class PlatformFFI {
F3? _session_get_rgba; F3? _session_get_rgba;
F4Dart? _session_get_rgba_size; F4Dart? _session_get_rgba_size;
F5Dart? _session_next_rgba; F5Dart? _session_next_rgba;
F6Dart? _session_register_texture;
static get localeName => Platform.localeName; static get localeName => Platform.localeName;
@ -130,6 +135,13 @@ class PlatformFFI {
malloc.free(a); malloc.free(a);
} }
void registerTexture(String id, int ptr) {
if (_session_register_texture == null) return;
final a = id.toNativeUtf8();
_session_register_texture!(a, ptr);
malloc.free(a);
}
/// Init the FFI class, loads the native Rust core library. /// Init the FFI class, loads the native Rust core library.
Future<void> init(String appType) async { Future<void> init(String appType) async {
_appType = appType; _appType = appType;
@ -150,6 +162,7 @@ class PlatformFFI {
dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size"); dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size");
_session_next_rgba = _session_next_rgba =
dylib.lookupFunction<F5, F5Dart>("session_next_rgba"); dylib.lookupFunction<F5, F5Dart>("session_next_rgba");
_session_register_texture = dylib.lookupFunction<F6, F6Dart>("session_register_texture");
try { try {
// SYSTEM user failed // SYSTEM user failed
_dir = (await getApplicationDocumentsDirectory()).path; _dir = (await getApplicationDocumentsDirectory()).path;

View File

@ -21,6 +21,8 @@ PODS:
- sqflite (0.0.2): - sqflite (0.0.2):
- FlutterMacOS - FlutterMacOS
- FMDB (>= 2.7.5) - FMDB (>= 2.7.5)
- texture_rgba_renderer (0.0.1):
- FlutterMacOS
- uni_links_desktop (0.0.1): - uni_links_desktop (0.0.1):
- FlutterMacOS - FlutterMacOS
- url_launcher_macos (0.0.1): - url_launcher_macos (0.0.1):
@ -42,6 +44,7 @@ DEPENDENCIES:
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`)
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
- texture_rgba_renderer (from `Flutter/ephemeral/.symlinks/plugins/texture_rgba_renderer/macos`)
- uni_links_desktop (from `Flutter/ephemeral/.symlinks/plugins/uni_links_desktop/macos`) - uni_links_desktop (from `Flutter/ephemeral/.symlinks/plugins/uni_links_desktop/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`) - wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`)
@ -71,6 +74,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
sqflite: sqflite:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
texture_rgba_renderer:
:path: Flutter/ephemeral/.symlinks/plugins/texture_rgba_renderer/macos
uni_links_desktop: uni_links_desktop:
:path: Flutter/ephemeral/.symlinks/plugins/uni_links_desktop/macos :path: Flutter/ephemeral/.symlinks/plugins/uni_links_desktop/macos
url_launcher_macos: url_launcher_macos:
@ -93,6 +98,7 @@ SPEC CHECKSUMS:
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
texture_rgba_renderer: cbed959a3c127122194a364e14b8577bd62dc8f2
uni_links_desktop: 45900fb319df48fcdea2df0756e9c2626696b026 uni_links_desktop: 45900fb319df48fcdea2df0756e9c2626696b026
url_launcher_macos: c04e4fa86382d4f94f6b38f14625708be3ae52e2 url_launcher_macos: c04e4fa86382d4f94f6b38f14625708be3ae52e2
wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9 wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9

View File

@ -17,6 +17,7 @@ import url_launcher_macos
import wakelock_macos import wakelock_macos
import window_manager import window_manager
import window_size import window_size
import texture_rgba_renderer
class MainFlutterWindow: NSWindow { class MainFlutterWindow: NSWindow {
override func awakeFromNib() { override func awakeFromNib() {
@ -49,6 +50,7 @@ class MainFlutterWindow: NSWindow {
UrlLauncherPlugin.register(with: controller.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: controller.registrar(forPlugin: "UrlLauncherPlugin"))
WakelockMacosPlugin.register(with: controller.registrar(forPlugin: "WakelockMacosPlugin")) WakelockMacosPlugin.register(with: controller.registrar(forPlugin: "WakelockMacosPlugin"))
WindowSizePlugin.register(with: controller.registrar(forPlugin: "WindowSizePlugin")) WindowSizePlugin.register(with: controller.registrar(forPlugin: "WindowSizePlugin"))
TextureRgbaRendererPlugin.register(with: controller.registrar(forPlugin: "TextureRgbaRendererPlugin"))
} }
super.awakeFromNib() super.awakeFromNib()

View File

@ -1563,5 +1563,5 @@ packages:
source: hosted source: hosted
version: "0.1.1" version: "0.1.1"
sdks: sdks:
dart: ">=2.18.0 <3.0.0" dart: ">=2.18.0 <4.0.0"
flutter: ">=3.3.0" flutter: ">=3.3.0"

View File

@ -2,6 +2,9 @@
#include <optional> #include <optional>
#include <desktop_multi_window/desktop_multi_window_plugin.h>
#include <texture_rgba_renderer/texture_rgba_renderer_plugin_c_api.h>
#include "flutter/generated_plugin_registrant.h" #include "flutter/generated_plugin_registrant.h"
FlutterWindow::FlutterWindow(const flutter::DartProject& project) FlutterWindow::FlutterWindow(const flutter::DartProject& project)
@ -25,6 +28,13 @@ bool FlutterWindow::OnCreate() {
return false; return false;
} }
RegisterPlugins(flutter_controller_->engine()); RegisterPlugins(flutter_controller_->engine());
DesktopMultiWindowSetWindowCreatedCallback([](void *controller) {
auto *flutter_view_controller =
reinterpret_cast<flutter::FlutterViewController *>(controller);
auto *registry = flutter_view_controller->engine();
TextureRgbaRendererPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("TextureRgbaRendererPlugin"));
});
SetChildContent(flutter_controller_->view()->GetNativeWindow()); SetChildContent(flutter_controller_->view()->GetNativeWindow());
return true; return true;
} }

View File

@ -11,7 +11,7 @@ use crate::hwcodec::*;
use crate::mediacodec::{ use crate::mediacodec::{
MediaCodecDecoder, MediaCodecDecoders, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT, MediaCodecDecoder, MediaCodecDecoders, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT,
}; };
use crate::vpxcodec::*; use crate::{vpxcodec::*, ImageFormat};
use hbb_common::{ use hbb_common::{
anyhow::anyhow, anyhow::anyhow,
@ -306,16 +306,17 @@ impl Decoder {
pub fn handle_video_frame( pub fn handle_video_frame(
&mut self, &mut self,
frame: &video_frame::Union, frame: &video_frame::Union,
fmt: ImageFormat,
rgb: &mut Vec<u8>, rgb: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
match frame { match frame {
video_frame::Union::Vp9s(vp9s) => { video_frame::Union::Vp9s(vp9s) => {
Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, rgb) Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, fmt, rgb)
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
video_frame::Union::H264s(h264s) => { video_frame::Union::H264s(h264s) => {
if let Some(decoder) = &mut self.hw.h264 { if let Some(decoder) = &mut self.hw.h264 {
Decoder::handle_hw_video_frame(decoder, h264s, rgb, &mut self.i420) Decoder::handle_hw_video_frame(decoder, h264s, fmt, rgb, &mut self.i420)
} else { } else {
Err(anyhow!("don't support h264!")) Err(anyhow!("don't support h264!"))
} }
@ -323,7 +324,7 @@ impl Decoder {
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
video_frame::Union::H265s(h265s) => { video_frame::Union::H265s(h265s) => {
if let Some(decoder) = &mut self.hw.h265 { if let Some(decoder) = &mut self.hw.h265 {
Decoder::handle_hw_video_frame(decoder, h265s, rgb, &mut self.i420) Decoder::handle_hw_video_frame(decoder, h265s, fmt, rgb, &mut self.i420)
} else { } else {
Err(anyhow!("don't support h265!")) Err(anyhow!("don't support h265!"))
} }
@ -331,7 +332,7 @@ impl Decoder {
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
video_frame::Union::H264s(h264s) => { video_frame::Union::H264s(h264s) => {
if let Some(decoder) = &mut self.media_codec.h264 { if let Some(decoder) = &mut self.media_codec.h264 {
Decoder::handle_mediacodec_video_frame(decoder, h264s, rgb) Decoder::handle_mediacodec_video_frame(decoder, h264s, fmt, rgb)
} else { } else {
Err(anyhow!("don't support h264!")) Err(anyhow!("don't support h264!"))
} }
@ -339,7 +340,7 @@ impl Decoder {
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
video_frame::Union::H265s(h265s) => { video_frame::Union::H265s(h265s) => {
if let Some(decoder) = &mut self.media_codec.h265 { if let Some(decoder) = &mut self.media_codec.h265 {
Decoder::handle_mediacodec_video_frame(decoder, h265s, rgb) Decoder::handle_mediacodec_video_frame(decoder, h265s, fmt, rgb)
} else { } else {
Err(anyhow!("don't support h265!")) Err(anyhow!("don't support h265!"))
} }
@ -351,6 +352,7 @@ impl Decoder {
fn handle_vp9s_video_frame( fn handle_vp9s_video_frame(
decoder: &mut VpxDecoder, decoder: &mut VpxDecoder,
vp9s: &EncodedVideoFrames, vp9s: &EncodedVideoFrames,
fmt: ImageFormat,
rgb: &mut Vec<u8>, rgb: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
let mut last_frame = Image::new(); let mut last_frame = Image::new();
@ -367,7 +369,7 @@ impl Decoder {
if last_frame.is_null() { if last_frame.is_null() {
Ok(false) Ok(false)
} else { } else {
last_frame.rgb(1, true, rgb); last_frame.to(fmt, 1, rgb);
Ok(true) Ok(true)
} }
} }
@ -376,14 +378,15 @@ impl Decoder {
fn handle_hw_video_frame( fn handle_hw_video_frame(
decoder: &mut HwDecoder, decoder: &mut HwDecoder,
frames: &EncodedVideoFrames, frames: &EncodedVideoFrames,
rgb: &mut Vec<u8>, fmt: ImageFormat,
raw: &mut Vec<u8>,
i420: &mut Vec<u8>, i420: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
let mut ret = false; let mut ret = false;
for h264 in frames.frames.iter() { for h264 in frames.frames.iter() {
for image in decoder.decode(&h264.data)? { for image in decoder.decode(&h264.data)? {
// TODO: just process the last frame // TODO: just process the last frame
if image.bgra(rgb, i420).is_ok() { if image.to_fmt(fmt, raw, i420).is_ok() {
ret = true; ret = true;
} }
} }
@ -395,11 +398,12 @@ impl Decoder {
fn handle_mediacodec_video_frame( fn handle_mediacodec_video_frame(
decoder: &mut MediaCodecDecoder, decoder: &mut MediaCodecDecoder,
frames: &EncodedVideoFrames, frames: &EncodedVideoFrames,
rgb: &mut Vec<u8>, fmt: ImageFormat,
raw: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
let mut ret = false; let mut ret = false;
for h264 in frames.frames.iter() { for h264 in frames.frames.iter() {
return decoder.decode(&h264.data, rgb); return decoder.decode(&h264.data, fmt, raw);
} }
return Ok(false); return Ok(false);
} }

View File

@ -103,6 +103,19 @@ extern "C" {
height: c_int, height: c_int,
) -> c_int; ) -> c_int;
pub fn I420ToABGR(
src_y: *const u8,
src_stride_y: c_int,
src_u: *const u8,
src_stride_u: c_int,
src_v: *const u8,
src_stride_v: c_int,
dst_rgba: *mut u8,
dst_stride_rgba: c_int,
width: c_int,
height: c_int,
) -> c_int;
pub fn NV12ToARGB( pub fn NV12ToARGB(
src_y: *const u8, src_y: *const u8,
src_stride_y: c_int, src_stride_y: c_int,
@ -113,6 +126,17 @@ extern "C" {
width: c_int, width: c_int,
height: c_int, height: c_int,
) -> c_int; ) -> c_int;
pub fn NV12ToABGR(
src_y: *const u8,
src_stride_y: c_int,
src_uv: *const u8,
src_stride_uv: c_int,
dst_rgba: *mut u8,
dst_stride_rgba: c_int,
width: c_int,
height: c_int,
) -> c_int;
} }
// https://github.com/webmproject/libvpx/blob/master/vpx/src/vpx_image.c // https://github.com/webmproject/libvpx/blob/master/vpx/src/vpx_image.c
@ -246,6 +270,7 @@ pub unsafe fn nv12_to_i420(
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
pub mod hw { pub mod hw {
use hbb_common::{anyhow::anyhow, ResultType}; use hbb_common::{anyhow::anyhow, ResultType};
use crate::ImageFormat;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat}; use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat};
@ -315,7 +340,8 @@ pub mod hw {
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub fn hw_nv12_to_bgra( pub fn hw_nv12_to(
fmt: ImageFormat,
width: usize, width: usize,
height: usize, height: usize,
src_y: &[u8], src_y: &[u8],
@ -355,18 +381,39 @@ pub mod hw {
width as _, width as _,
height as _, height as _,
); );
super::I420ToARGB( match fmt {
i420_offset_y, ImageFormat::ARGB => {
i420_stride_y, super::I420ToARGB(
i420_offset_u, i420_offset_y,
i420_stride_u, i420_stride_y,
i420_offset_v, i420_offset_u,
i420_stride_v, i420_stride_u,
dst.as_mut_ptr(), i420_offset_v,
(width * 4) as _, i420_stride_v,
width as _, dst.as_mut_ptr(),
height as _, (width * 4) as _,
); width as _,
height as _,
);
}
ImageFormat::ABGR => {
super::I420ToABGR(
i420_offset_y,
i420_stride_y,
i420_offset_u,
i420_stride_u,
i420_offset_v,
i420_stride_v,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
}
_ => {
return Err(anyhow!("unsupported image format"));
}
}
return Ok(()); return Ok(());
}; };
} }
@ -374,7 +421,8 @@ pub mod hw {
} }
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub fn hw_nv12_to_bgra( pub fn hw_nv12_to(
fmt: ImageFormat,
width: usize, width: usize,
height: usize, height: usize,
src_y: &[u8], src_y: &[u8],
@ -387,23 +435,46 @@ pub mod hw {
) -> ResultType<()> { ) -> ResultType<()> {
dst.resize(width * height * 4, 0); dst.resize(width * height * 4, 0);
unsafe { unsafe {
match super::NV12ToARGB( match fmt {
src_y.as_ptr(), ImageFormat::ARGB => {
src_stride_y as _, match super::NV12ToARGB(
src_uv.as_ptr(), src_y.as_ptr(),
src_stride_uv as _, src_stride_y as _,
dst.as_mut_ptr(), src_uv.as_ptr(),
(width * 4) as _, src_stride_uv as _,
width as _, dst.as_mut_ptr(),
height as _, (width * 4) as _,
) { width as _,
0 => Ok(()), height as _,
_ => Err(anyhow!("NV12ToARGB failed")), ) {
0 => Ok(()),
_ => Err(anyhow!("NV12ToARGB failed")),
}
}
ImageFormat::ABGR => {
match super::NV12ToABGR(
src_y.as_ptr(),
src_stride_y as _,
src_uv.as_ptr(),
src_stride_uv as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
) {
0 => Ok(()),
_ => Err(anyhow!("NV12ToABGR failed")),
}
}
_ => {
Err(anyhow!("unsupported image format"))
}
} }
} }
} }
pub fn hw_i420_to_bgra( pub fn hw_i420_to(
fmt: ImageFormat,
width: usize, width: usize,
height: usize, height: usize,
src_y: &[u8], src_y: &[u8],
@ -419,18 +490,38 @@ pub mod hw {
let src_v = src_v.as_ptr(); let src_v = src_v.as_ptr();
dst.resize(width * height * 4, 0); dst.resize(width * height * 4, 0);
unsafe { unsafe {
super::I420ToARGB( match fmt {
src_y, ImageFormat::ARGB => {
src_stride_y as _, super::I420ToARGB(
src_u, src_y,
src_stride_u as _, src_stride_y as _,
src_v, src_u,
src_stride_v as _, src_stride_u as _,
dst.as_mut_ptr(), src_v,
(width * 4) as _, src_stride_v as _,
width as _, dst.as_mut_ptr(),
height as _, (width * 4) as _,
); width as _,
height as _,
);
}
ImageFormat::ABGR => {
super::I420ToABGR(
src_y,
src_stride_y as _,
src_u,
src_stride_u as _,
src_v,
src_stride_v as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
}
_ => {
}
}
}; };
} }
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
codec::{EncoderApi, EncoderCfg}, codec::{EncoderApi, EncoderCfg},
hw, HW_STRIDE_ALIGN, hw, ImageFormat, HW_STRIDE_ALIGN,
}; };
use hbb_common::{ use hbb_common::{
anyhow::{anyhow, Context}, anyhow::{anyhow, Context},
@ -236,22 +236,24 @@ pub struct HwDecoderImage<'a> {
} }
impl HwDecoderImage<'_> { impl HwDecoderImage<'_> {
pub fn bgra(&self, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> { pub fn to_fmt(&self, fmt: ImageFormat, fmt_data: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
let frame = self.frame; let frame = self.frame;
match frame.pixfmt { match frame.pixfmt {
AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to_bgra( AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to(
fmt,
frame.width as _, frame.width as _,
frame.height as _, frame.height as _,
&frame.data[0], &frame.data[0],
&frame.data[1], &frame.data[1],
frame.linesize[0] as _, frame.linesize[0] as _,
frame.linesize[1] as _, frame.linesize[1] as _,
bgra, fmt_data,
i420, i420,
HW_STRIDE_ALIGN, HW_STRIDE_ALIGN,
), ),
AVPixelFormat::AV_PIX_FMT_YUV420P => { AVPixelFormat::AV_PIX_FMT_YUV420P => {
hw::hw_i420_to_bgra( hw::hw_i420_to(
fmt,
frame.width as _, frame.width as _,
frame.height as _, frame.height as _,
&frame.data[0], &frame.data[0],
@ -260,12 +262,20 @@ impl HwDecoderImage<'_> {
frame.linesize[0] as _, frame.linesize[0] as _,
frame.linesize[1] as _, frame.linesize[1] as _,
frame.linesize[2] as _, frame.linesize[2] as _,
bgra, fmt_data,
); );
return Ok(()); return Ok(());
} }
} }
} }
pub fn bgra(&self, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
self.to_fmt(ImageFormat::ARGB, bgra, i420)
}
pub fn rgba(&self, rgba: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
self.to_fmt(ImageFormat::ABGR, rgba, i420)
}
} }
fn get_config(k: &str) -> ResultType<CodecInfos> { fn get_config(k: &str) -> ResultType<CodecInfos> {

View File

@ -1,5 +1,4 @@
use hbb_common::anyhow::Error; use hbb_common::{log, anyhow::Error, bail, ResultType};
use hbb_common::{bail, ResultType};
use ndk::media::media_codec::{MediaCodec, MediaCodecDirection, MediaFormat}; use ndk::media::media_codec::{MediaCodec, MediaCodecDirection, MediaFormat};
use std::ops::Deref; use std::ops::Deref;
use std::{ use std::{
@ -8,9 +7,10 @@ use std::{
time::Duration, time::Duration,
}; };
use crate::ImageFormat;
use crate::{ use crate::{
codec::{EncoderApi, EncoderCfg}, codec::{EncoderApi, EncoderCfg},
I420ToARGB, I420ToABGR, I420ToARGB,
}; };
/// MediaCodec mime type name /// MediaCodec mime type name
@ -50,7 +50,7 @@ impl MediaCodecDecoder {
MediaCodecDecoders { h264, h265 } MediaCodecDecoders { h264, h265 }
} }
pub fn decode(&mut self, data: &[u8], rgb: &mut Vec<u8>) -> ResultType<bool> { pub fn decode(&mut self, data: &[u8], fmt: ImageFormat, raw: &mut Vec<u8>) -> ResultType<bool> {
match self.dequeue_input_buffer(Duration::from_millis(10))? { match self.dequeue_input_buffer(Duration::from_millis(10))? {
Some(mut input_buffer) => { Some(mut input_buffer) => {
let mut buf = input_buffer.buffer_mut(); let mut buf = input_buffer.buffer_mut();
@ -83,23 +83,44 @@ impl MediaCodecDecoder {
let bps = 4; let bps = 4;
let u = buf.len() * 2 / 3; let u = buf.len() * 2 / 3;
let v = buf.len() * 5 / 6; let v = buf.len() * 5 / 6;
rgb.resize(h * w * bps, 0); raw.resize(h * w * bps, 0);
let y_ptr = buf.as_ptr(); let y_ptr = buf.as_ptr();
let u_ptr = buf[u..].as_ptr(); let u_ptr = buf[u..].as_ptr();
let v_ptr = buf[v..].as_ptr(); let v_ptr = buf[v..].as_ptr();
unsafe { unsafe {
I420ToARGB( match fmt {
y_ptr, ImageFormat::ARGB => {
stride, I420ToARGB(
u_ptr, y_ptr,
stride / 2, stride,
v_ptr, u_ptr,
stride / 2, stride / 2,
rgb.as_mut_ptr(), v_ptr,
(w * bps) as _, stride / 2,
w as _, raw.as_mut_ptr(),
h as _, (w * bps) as _,
); w as _,
h as _,
);
}
ImageFormat::ARGB => {
I420ToABGR(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
raw.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
}
_ => {
bail!("Unsupported image format");
}
}
} }
self.release_output_buffer(output_buffer, false)?; self.release_output_buffer(output_buffer, false)?;
Ok(true) Ok(true)

View File

@ -43,6 +43,13 @@ pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer
pub mod record; pub mod record;
mod vpx; mod vpx;
#[derive(Copy, Clone)]
pub enum ImageFormat {
Raw,
ABGR,
ARGB,
}
#[inline] #[inline]
pub fn would_block_if_equal(old: &mut Vec<u8>, b: &[u8]) -> std::io::Result<()> { pub fn would_block_if_equal(old: &mut Vec<u8>, b: &[u8]) -> std::io::Result<()> {
// does this really help? // does this really help?

View File

@ -6,8 +6,8 @@ use hbb_common::anyhow::{anyhow, Context};
use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame}; use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame};
use hbb_common::{get_time, ResultType}; use hbb_common::{get_time, ResultType};
use crate::codec::EncoderApi;
use crate::STRIDE_ALIGN; use crate::STRIDE_ALIGN;
use crate::{codec::EncoderApi, ImageFormat};
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *}; use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
use hbb_common::bytes::Bytes; use hbb_common::bytes::Bytes;
@ -417,7 +417,7 @@ impl VpxDecoder {
Ok(Self { ctx }) Ok(Self { ctx })
} }
pub fn decode2rgb(&mut self, data: &[u8], rgba: bool) -> Result<Vec<u8>> { pub fn decode2rgb(&mut self, data: &[u8], fmt: ImageFormat) -> Result<Vec<u8>> {
let mut img = Image::new(); let mut img = Image::new();
for frame in self.decode(data)? { for frame in self.decode(data)? {
drop(img); drop(img);
@ -431,7 +431,7 @@ impl VpxDecoder {
Ok(Vec::new()) Ok(Vec::new())
} else { } else {
let mut out = Default::default(); let mut out = Default::default();
img.rgb(1, rgba, &mut out); img.to(fmt, 1, &mut out);
Ok(out) Ok(out)
} }
} }
@ -539,40 +539,60 @@ impl Image {
self.inner().stride[iplane] self.inner().stride[iplane]
} }
pub fn rgb(&self, stride_align: usize, rgba: bool, dst: &mut Vec<u8>) { pub fn to(&self, fmt: ImageFormat, stride_align: usize, dst: &mut Vec<u8>) {
let h = self.height(); let h = self.height();
let mut w = self.width(); let mut w = self.width();
let bps = if rgba { 4 } else { 3 }; let bps = match fmt {
ImageFormat::Raw => 3,
ImageFormat::ARGB | ImageFormat::ABGR => 4,
};
w = (w + stride_align - 1) & !(stride_align - 1); w = (w + stride_align - 1) & !(stride_align - 1);
dst.resize(h * w * bps, 0); dst.resize(h * w * bps, 0);
let img = self.inner(); let img = self.inner();
unsafe { unsafe {
if rgba { match fmt {
super::I420ToARGB( ImageFormat::Raw => {
img.planes[0], super::I420ToRAW(
img.stride[0], img.planes[0],
img.planes[1], img.stride[0],
img.stride[1], img.planes[1],
img.planes[2], img.stride[1],
img.stride[2], img.planes[2],
dst.as_mut_ptr(), img.stride[2],
(w * bps) as _, dst.as_mut_ptr(),
self.width() as _, (w * bps) as _,
self.height() as _, self.width() as _,
); self.height() as _,
} else { );
super::I420ToRAW( }
img.planes[0], ImageFormat::ARGB => {
img.stride[0], super::I420ToARGB(
img.planes[1], img.planes[0],
img.stride[1], img.stride[0],
img.planes[2], img.planes[1],
img.stride[2], img.stride[1],
dst.as_mut_ptr(), img.planes[2],
(w * bps) as _, img.stride[2],
self.width() as _, dst.as_mut_ptr(),
self.height() as _, (w * bps) as _,
); self.width() as _,
self.height() as _,
);
}
ImageFormat::ABGR => {
super::I420ToABGR(
img.planes[0],
img.stride[0],
img.planes[1],
img.stride[1],
img.planes[2],
img.stride[2],
dst.as_mut_ptr(),
(w * bps) as _,
self.width() as _,
self.height() as _,
);
}
} }
} }
} }

View File

@ -45,6 +45,7 @@ use scrap::{
codec::{Decoder, DecoderCfg}, codec::{Decoder, DecoderCfg},
record::{Recorder, RecorderContext}, record::{Recorder, RecorderContext},
VpxDecoderConfig, VpxVideoCodecId, VpxDecoderConfig, VpxVideoCodecId,
ImageFormat,
}; };
use crate::{ use crate::{
@ -943,7 +944,12 @@ impl VideoHandler {
} }
match &vf.union { match &vf.union {
Some(frame) => { Some(frame) => {
let res = self.decoder.handle_video_frame(frame, &mut self.rgb); // windows && flutter_texture_render, fmt is ImageFormat::ABGR
#[cfg(all(target_os = "windows", feature = "flutter_texture_render"))]
let fmt = ImageFormat::ABGR;
#[cfg(not(all(target_os = "windows", feature = "flutter_texture_render")))]
let fmt = ImageFormat::ARGB;
let res = self.decoder.handle_video_frame(frame, fmt, &mut self.rgb);
if self.record { if self.record {
self.recorder self.recorder
.lock() .lock()

View File

@ -3,12 +3,21 @@ use crate::{
flutter_ffi::EventToUI, flutter_ffi::EventToUI,
ui_session_interface::{io_loop, InvokeUiSession, Session}, ui_session_interface::{io_loop, InvokeUiSession, Session},
}; };
#[cfg(feature = "flutter_texture_render")]
use dlopen::{
symbor::{Library, Symbol},
Error as LibError,
};
use flutter_rust_bridge::StreamSink; use flutter_rust_bridge::StreamSink;
#[cfg(feature = "flutter_texture_render")]
use hbb_common::libc::c_void;
use hbb_common::{ use hbb_common::{
bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType, bail, config::LocalConfig, get_version_number, log, message_proto::*,
ResultType, rendezvous_proto::ConnType, ResultType,
}; };
use serde_json::json; use serde_json::json;
#[cfg(not(feature = "flutter_texture_render"))]
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::{ use std::{
collections::HashMap, collections::HashMap,
@ -29,6 +38,21 @@ lazy_static::lazy_static! {
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
} }
#[cfg(all(target_os = "windows", feature = "flutter_texture_render"))]
lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("texture_rgba_renderer_plugin.dll");
}
#[cfg(all(target_os = "linux", feature = "flutter_texture_render"))]
lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("libtexture_rgba_renderer_plugin.so");
}
#[cfg(all(target_os = "macos", feature = "flutter_texture_render"))]
lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open_self();
}
/// FFI for rustdesk core's main entry. /// FFI for rustdesk core's main entry.
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit. /// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
#[cfg(not(windows))] #[cfg(not(windows))]
@ -108,6 +132,16 @@ pub unsafe extern "C" fn free_c_args(ptr: *mut *mut c_char, len: c_int) {
// Afterwards the vector will be dropped and thus freed. // Afterwards the vector will be dropped and thus freed.
} }
#[cfg(feature = "flutter_texture_render")]
#[derive(Default, Clone)]
pub struct FlutterHandler {
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
notify_rendered: Arc<RwLock<bool>>,
renderer: Arc<RwLock<VideoRenderer>>,
peer_info: Arc<RwLock<PeerInfo>>,
}
#[cfg(not(feature = "flutter_texture_render"))]
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct FlutterHandler { pub struct FlutterHandler {
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>, pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
@ -115,6 +149,84 @@ pub struct FlutterHandler {
// We must check the `rgba_valid` before reading [rgba]. // We must check the `rgba_valid` before reading [rgba].
pub rgba: Arc<RwLock<Vec<u8>>>, pub rgba: Arc<RwLock<Vec<u8>>>,
pub rgba_valid: Arc<AtomicBool>, pub rgba_valid: Arc<AtomicBool>,
peer_info: Arc<RwLock<PeerInfo>>,
}
#[cfg(feature = "flutter_texture_render")]
pub type FlutterRgbaRendererPluginOnRgba =
unsafe extern "C" fn(texture_rgba: *mut c_void, buffer: *const u8, width: c_int, height: c_int);
// Video Texture Renderer in Flutter
#[cfg(feature = "flutter_texture_render")]
#[derive(Clone)]
struct VideoRenderer {
// TextureRgba pointer in flutter native.
ptr: usize,
width: i32,
height: i32,
data_len: usize,
on_rgba_func: Option<Symbol<'static, FlutterRgbaRendererPluginOnRgba>>,
}
#[cfg(feature = "flutter_texture_render")]
impl Default for VideoRenderer {
fn default() -> Self {
let on_rgba_func = match &*TEXTURE_RGBA_RENDERER_PLUGIN {
Ok(lib) => {
let find_sym_res = unsafe {
lib.symbol::<FlutterRgbaRendererPluginOnRgba>("FlutterRgbaRendererPluginOnRgba")
};
match find_sym_res {
Ok(sym) => Some(sym),
Err(e) => {
log::error!("Failed to find symbol FlutterRgbaRendererPluginOnRgba, {e}");
None
}
}
}
Err(e) => {
log::error!("Failed to load texture rgba renderer plugin, {e}");
None
}
};
Self {
ptr: 0,
width: 0,
height: 0,
data_len: 0,
on_rgba_func,
}
}
}
#[cfg(feature = "flutter_texture_render")]
impl VideoRenderer {
#[inline]
pub fn set_size(&mut self, width: i32, height: i32) {
self.width = width;
self.height = height;
self.data_len = if width > 0 && height > 0 {
(width * height * 4) as usize
} else {
0
};
}
pub fn on_rgba(&self, rgba: &Vec<u8>) {
if self.ptr == usize::default() || rgba.len() != self.data_len {
return;
}
if let Some(func) = &self.on_rgba_func {
unsafe {
func(
self.ptr as _,
rgba.as_ptr() as _,
self.width as _,
self.height as _,
)
};
}
}
} }
impl FlutterHandler { impl FlutterHandler {
@ -156,6 +268,19 @@ impl FlutterHandler {
} }
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned()) serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
} }
#[inline]
#[cfg(feature = "flutter_texture_render")]
pub fn register_texture(&mut self, ptr: usize) {
self.renderer.write().unwrap().ptr = ptr;
}
#[inline]
#[cfg(feature = "flutter_texture_render")]
pub fn set_size(&mut self, width: i32, height: i32) {
*self.notify_rendered.write().unwrap() = false;
self.renderer.write().unwrap().set_size(width, height);
}
} }
impl InvokeUiSession for FlutterHandler { impl InvokeUiSession for FlutterHandler {
@ -315,6 +440,8 @@ impl InvokeUiSession for FlutterHandler {
// unused in flutter // unused in flutter
fn adapt_size(&self) {} fn adapt_size(&self) {}
#[inline]
#[cfg(not(feature = "flutter_texture_render"))]
fn on_rgba(&self, data: &mut Vec<u8>) { fn on_rgba(&self, data: &mut Vec<u8>) {
// If the current rgba is not fetched by flutter, i.e., is valid. // If the current rgba is not fetched by flutter, i.e., is valid.
// We give up sending a new event to flutter. // We give up sending a new event to flutter.
@ -329,6 +456,19 @@ impl InvokeUiSession for FlutterHandler {
} }
} }
#[inline]
#[cfg(feature = "flutter_texture_render")]
fn on_rgba(&self, data: &mut Vec<u8>) {
self.renderer.read().unwrap().on_rgba(data);
if *self.notify_rendered.read().unwrap() {
return;
}
if let Some(stream) = &*self.event_stream.read().unwrap() {
stream.add(EventToUI::Rgba);
*self.notify_rendered.write().unwrap() = true;
}
}
fn set_peer_info(&self, pi: &PeerInfo) { fn set_peer_info(&self, pi: &PeerInfo) {
let displays = Self::make_displays_msg(&pi.displays); let displays = Self::make_displays_msg(&pi.displays);
let mut features: HashMap<&str, i32> = Default::default(); let mut features: HashMap<&str, i32> = Default::default();
@ -340,6 +480,7 @@ impl InvokeUiSession for FlutterHandler {
features.insert("privacy_mode", 0); features.insert("privacy_mode", 0);
} }
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned()); let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
*self.peer_info.write().unwrap() = pi.clone();
self.push_event( self.push_event(
"peer_info", "peer_info",
vec![ vec![
@ -356,6 +497,7 @@ impl InvokeUiSession for FlutterHandler {
} }
fn set_displays(&self, displays: &Vec<DisplayInfo>) { fn set_displays(&self, displays: &Vec<DisplayInfo>) {
self.peer_info.write().unwrap().displays = displays.clone();
self.push_event( self.push_event(
"sync_peer_info", "sync_peer_info",
vec![("displays", &Self::make_displays_msg(displays))], vec![("displays", &Self::make_displays_msg(displays))],
@ -444,6 +586,7 @@ impl InvokeUiSession for FlutterHandler {
#[inline] #[inline]
fn get_rgba(&self) -> *const u8 { fn get_rgba(&self) -> *const u8 {
#[cfg(not(feature = "flutter_texture_render"))]
if self.rgba_valid.load(Ordering::Relaxed) { if self.rgba_valid.load(Ordering::Relaxed) {
return self.rgba.read().unwrap().as_ptr(); return self.rgba.read().unwrap().as_ptr();
} }
@ -451,7 +594,8 @@ impl InvokeUiSession for FlutterHandler {
} }
#[inline] #[inline]
fn next_rgba(&mut self) { fn next_rgba(&self) {
#[cfg(not(feature = "flutter_texture_render"))]
self.rgba_valid.store(false, Ordering::Relaxed); self.rgba_valid.store(false, Ordering::Relaxed);
} }
} }
@ -517,6 +661,13 @@ pub fn session_add(
/// * `events2ui` - The events channel to ui. /// * `events2ui` - The events channel to ui.
pub fn session_start_(id: &str, event_stream: StreamSink<EventToUI>) -> ResultType<()> { pub fn session_start_(id: &str, event_stream: StreamSink<EventToUI>) -> ResultType<()> {
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(id) {
#[cfg(feature = "flutter_texture_render")]
log::info!(
"Session {} start, render by flutter texture rgba plugin",
id
);
#[cfg(not(feature = "flutter_texture_render"))]
log::info!("Session {} start, render by flutter paint widget", id);
*session.event_stream.write().unwrap() = Some(event_stream); *session.event_stream.write().unwrap() = Some(event_stream);
let session = session.clone(); let session = session.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
@ -711,21 +862,28 @@ pub fn set_cur_session_id(id: String) {
} }
#[no_mangle] #[no_mangle]
#[cfg(not(feature = "flutter_texture_render"))]
pub fn session_get_rgba_size(id: *const char) -> usize { pub fn session_get_rgba_size(id: *const char) -> usize {
let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; let id = unsafe { std::ffi::CStr::from_ptr(id as _) };
if let Ok(id) = id.to_str() { if let Ok(id) = id.to_str() {
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { if let Some(session) = SESSIONS.read().unwrap().get(id) {
return session.rgba.read().unwrap().len(); return session.rgba.read().unwrap().len();
} }
} }
0 0
} }
#[no_mangle]
#[cfg(feature = "flutter_texture_render")]
pub fn session_get_rgba_size(_id: *const char) -> usize {
0
}
#[no_mangle] #[no_mangle]
pub fn session_get_rgba(id: *const char) -> *const u8 { pub fn session_get_rgba(id: *const char) -> *const u8 {
let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; let id = unsafe { std::ffi::CStr::from_ptr(id as _) };
if let Ok(id) = id.to_str() { if let Ok(id) = id.to_str() {
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { if let Some(session) = SESSIONS.read().unwrap().get(id) {
return session.get_rgba(); return session.get_rgba();
} }
} }
@ -736,8 +894,23 @@ pub fn session_get_rgba(id: *const char) -> *const u8 {
pub fn session_next_rgba(id: *const char) { pub fn session_next_rgba(id: *const char) {
let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; let id = unsafe { std::ffi::CStr::from_ptr(id as _) };
if let Ok(id) = id.to_str() { if let Ok(id) = id.to_str() {
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { if let Some(session) = SESSIONS.read().unwrap().get(id) {
return session.next_rgba(); return session.next_rgba();
} }
} }
} }
#[no_mangle]
#[cfg(feature = "flutter_texture_render")]
pub fn session_register_texture(id: *const char, ptr: usize) {
let id = unsafe { std::ffi::CStr::from_ptr(id as _) };
if let Ok(id) = id.to_str() {
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) {
return session.register_texture(ptr);
}
}
}
#[no_mangle]
#[cfg(not(feature = "flutter_texture_render"))]
pub fn session_register_texture(_id: *const char, _ptr: usize) {}

View File

@ -529,6 +529,13 @@ pub fn session_switch_sides(id: String) {
} }
} }
pub fn session_set_size(_id: String, _width: i32, _height: i32) {
#[cfg(feature = "flutter_texture_render")]
if let Some(session) = SESSIONS.write().unwrap().get_mut(&_id) {
session.set_size(_width, _height);
}
}
pub fn main_get_sound_inputs() -> Vec<String> { pub fn main_get_sound_inputs() -> Vec<String> {
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
return get_sound_inputs(); return get_sound_inputs();
@ -1300,6 +1307,17 @@ pub fn main_hide_docker() -> SyncReturn<bool> {
SyncReturn(true) SyncReturn(true)
} }
pub fn main_use_texture_render() -> SyncReturn<bool> {
#[cfg(not(feature = "flutter_texture_render"))]
{
SyncReturn(false)
}
#[cfg(feature = "flutter_texture_render")]
{
SyncReturn(true)
}
}
pub fn cm_start_listen_ipc_thread() { pub fn cm_start_listen_ipc_thread() {
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
crate::flutter::connection_manager::start_listen_ipc_thread(); crate::flutter::connection_manager::start_listen_ipc_thread();

View File

@ -298,7 +298,7 @@ impl InvokeUiSession for SciterHandler {
std::ptr::null() std::ptr::null()
} }
fn next_rgba(&mut self) {} fn next_rgba(&self) {}
} }
pub struct SciterSession(Session<SciterHandler>); pub struct SciterSession(Session<SciterHandler>);

View File

@ -798,7 +798,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn on_voice_call_waiting(&self); fn on_voice_call_waiting(&self);
fn on_voice_call_incoming(&self); fn on_voice_call_incoming(&self);
fn get_rgba(&self) -> *const u8; fn get_rgba(&self) -> *const u8;
fn next_rgba(&mut self); fn next_rgba(&self);
} }
impl<T: InvokeUiSession> Deref for Session<T> { impl<T: InvokeUiSession> Deref for Session<T> {