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)
# no need mock on x86_64
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
@ -761,7 +761,7 @@ jobs:
ln -s /usr/include /vcpkg/installed/arm64-linux/include
export VCPKG_ROOT=/vcpkg
# 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)
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
export VCPKG_ROOT=/vcpkg
# 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

View File

@ -732,7 +732,7 @@ jobs:
x86_64)
# no need mock on x86_64
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
@ -900,7 +900,7 @@ jobs:
ln -s /usr/include /vcpkg/installed/arm64-linux/include
export VCPKG_ROOT=/vcpkg
# 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)
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
export VCPKG_ROOT=/vcpkg
# 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

327
Cargo.lock generated
View File

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

View File

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

View File

@ -239,6 +239,7 @@ def get_features(args):
features.append('hwcodec')
if args.flutter:
features.append('flutter')
features.append('flutter_texture_render')
if args.flatpak:
features.append('flatpak')
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_svg/flutter_svg.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_desktop/uni_links_desktop.dart';
import 'package:url_launcher/url_launcher.dart';
@ -44,6 +45,10 @@ var isWeb = false;
var isWebDesktop = false;
var version = "";
int androidVersion = 0;
/// Incriment count for textureId.
int _textureId = 0;
int get newTextureId => _textureId ++;
final textureRenderer = TextureRgbaRenderer();
/// only available for Windows target
int windowsBuildNumber = 0;

View File

@ -63,6 +63,9 @@ class _RemotePageState extends State<RemotePage>
late RxBool _zoomCursor;
late RxBool _remoteCursorMoved;
late RxBool _keyboardEnabled;
late RxInt _textureId;
late int _textureKey;
final useTextureRender = bind.mainUseTextureRender();
final _blockableOverlayState = BlockableOverlayState();
@ -85,6 +88,8 @@ class _RemotePageState extends State<RemotePage>
_showRemoteCursor = ShowRemoteCursorState.find(id);
_keyboardEnabled = KeyboardEnabledState.find(id);
_remoteCursorMoved = RemoteCursorMovedState.find(id);
_textureKey = newTextureId;
_textureId = RxInt(-1);
}
void _removeStates(String id) {
@ -119,6 +124,18 @@ class _RemotePageState extends State<RemotePage>
if (!Platform.isLinux) {
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.qualityMonitorModel.checkShowQualityMonitor(widget.id);
// Session option should be set after models.dart/FFI.start
@ -183,6 +200,10 @@ class _RemotePageState extends State<RemotePage>
@override
void dispose() {
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
bind.sessionEnterOrLeave(id: widget.id, enter: false);
DesktopMultiWindow.removeListener(this);
@ -346,6 +367,8 @@ class _RemotePageState extends State<RemotePage>
cursorOverImage: _cursorOverImage,
keyboardEnabled: _keyboardEnabled,
remoteCursorMoved: _remoteCursorMoved,
textureId: _textureId,
useTextureRender: useTextureRender,
listenerBuilder: (child) =>
_buildRawPointerMouseRegion(child, enterView, leaveView),
);
@ -383,6 +406,8 @@ class ImagePaint extends StatefulWidget {
final RxBool cursorOverImage;
final RxBool keyboardEnabled;
final RxBool remoteCursorMoved;
final RxInt textureId;
final bool useTextureRender;
final Widget Function(Widget)? listenerBuilder;
ImagePaint(
@ -392,6 +417,8 @@ class ImagePaint extends StatefulWidget {
required this.cursorOverImage,
required this.keyboardEnabled,
required this.remoteCursorMoved,
required this.textureId,
required this.useTextureRender,
this.listenerBuilder})
: super(key: key);
@ -466,10 +493,19 @@ class _ImagePaintState extends State<ImagePaint> {
final imageWidth = c.getDisplayWidth() * s;
final imageHeight = c.getDisplayHeight() * s;
final imageSize = Size(imageWidth, imageHeight);
final imageWidget = CustomPaint(
size: imageSize,
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
);
late final Widget imageWidget;
if (widget.useTextureRender) {
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>(
onNotification: (notification) {
@ -493,11 +529,31 @@ class _ImagePaintState extends State<ImagePaint> {
context, _buildListener(imageWidget), c.size, imageSize)),
));
} else {
final 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));
late final Widget imageWidget;
if (c.size.width > 0 && c.size.height > 0) {
if (widget.useTextureRender) {
imageWidget = Stack(
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);
}
_updateSessionWidthHeight(peerId, display.width, display.height);
try {
CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
} 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].
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)
@ -420,6 +426,7 @@ class FfiModel with ChangeNotifier {
stateGlobal.displaysCount.value = _pi.displays.length;
if (_pi.currentDisplay < _pi.displays.length) {
_display = _pi.displays[_pi.currentDisplay];
_updateSessionWidthHeight(peerId, display.width, display.height);
}
if (displays.isNotEmpty) {
parent.target?.dialogManager.showLoading(
@ -485,19 +492,18 @@ class ImageModel with ChangeNotifier {
WeakReference<FFI> parent;
final List<Function(String)> _callbacksOnFirstImage = [];
final List<Function(String)> callbacksOnFirstImage = [];
ImageModel(this.parent);
addCallbackOnFirstImage(Function(String) cb) =>
_callbacksOnFirstImage.add(cb);
addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
onRgba(Uint8List rgba) {
if (_waitForImage[id]!) {
_waitForImage[id] = false;
parent.target?.dialogManager.dismissAll();
if (isDesktop) {
for (final cb in _callbacksOnFirstImage) {
for (final cb in callbacksOnFirstImage) {
cb(id);
}
}
@ -1432,6 +1438,7 @@ class FFI {
final stream = bind.sessionStart(id: id);
final cb = ffiModel.startEventListener(id);
() async {
final useTextureRender = bind.mainUseTextureRender();
// Preserved for the rgba data.
await for (final message in stream) {
if (message is EventToUI_Event) {
@ -1445,14 +1452,26 @@ class FFI {
debugPrint('json.decode fail1(): $e, ${message.field0}');
}
} else if (message is EventToUI_Rgba) {
// 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);
if (useTextureRender) {
if (_waitForImage[id]!) {
_waitForImage[id] = false;
dialogManager.dismissAll();
for (final cb in imageModel.callbacksOnFirstImage) {
cb(id);
}
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 F5Dart = void Function(Pointer<Utf8>);
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.
/// Hides the platform differences.
@ -52,6 +55,8 @@ class PlatformFFI {
F3? _session_get_rgba;
F4Dart? _session_get_rgba_size;
F5Dart? _session_next_rgba;
F6Dart? _session_register_texture;
static get localeName => Platform.localeName;
@ -130,6 +135,13 @@ class PlatformFFI {
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.
Future<void> init(String appType) async {
_appType = appType;
@ -150,6 +162,7 @@ class PlatformFFI {
dylib.lookupFunction<F4, F4Dart>("session_get_rgba_size");
_session_next_rgba =
dylib.lookupFunction<F5, F5Dart>("session_next_rgba");
_session_register_texture = dylib.lookupFunction<F6, F6Dart>("session_register_texture");
try {
// SYSTEM user failed
_dir = (await getApplicationDocumentsDirectory()).path;

View File

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

View File

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

View File

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

View File

@ -2,6 +2,9 @@
#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"
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
@ -25,6 +28,13 @@ bool FlutterWindow::OnCreate() {
return false;
}
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());
return true;
}

View File

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

View File

@ -103,6 +103,19 @@ extern "C" {
height: 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(
src_y: *const u8,
src_stride_y: c_int,
@ -113,6 +126,17 @@ extern "C" {
width: c_int,
height: 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
@ -246,6 +270,7 @@ pub unsafe fn nv12_to_i420(
#[cfg(feature = "hwcodec")]
pub mod hw {
use hbb_common::{anyhow::anyhow, ResultType};
use crate::ImageFormat;
#[cfg(target_os = "windows")]
use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat};
@ -315,7 +340,8 @@ pub mod hw {
}
#[cfg(target_os = "windows")]
pub fn hw_nv12_to_bgra(
pub fn hw_nv12_to(
fmt: ImageFormat,
width: usize,
height: usize,
src_y: &[u8],
@ -355,18 +381,39 @@ pub mod hw {
width as _,
height as _,
);
super::I420ToARGB(
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 _,
);
match fmt {
ImageFormat::ARGB => {
super::I420ToARGB(
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 _,
);
}
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(());
};
}
@ -374,7 +421,8 @@ pub mod hw {
}
#[cfg(not(target_os = "windows"))]
pub fn hw_nv12_to_bgra(
pub fn hw_nv12_to(
fmt: ImageFormat,
width: usize,
height: usize,
src_y: &[u8],
@ -387,23 +435,46 @@ pub mod hw {
) -> ResultType<()> {
dst.resize(width * height * 4, 0);
unsafe {
match super::NV12ToARGB(
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!("NV12ToARGB failed")),
match fmt {
ImageFormat::ARGB => {
match super::NV12ToARGB(
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!("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,
height: usize,
src_y: &[u8],
@ -419,18 +490,38 @@ pub mod hw {
let src_v = src_v.as_ptr();
dst.resize(width * height * 4, 0);
unsafe {
super::I420ToARGB(
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 _,
);
match fmt {
ImageFormat::ARGB => {
super::I420ToARGB(
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 _,
);
}
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::{
codec::{EncoderApi, EncoderCfg},
hw, HW_STRIDE_ALIGN,
hw, ImageFormat, HW_STRIDE_ALIGN,
};
use hbb_common::{
anyhow::{anyhow, Context},
@ -236,22 +236,24 @@ pub struct HwDecoderImage<'a> {
}
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;
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.height as _,
&frame.data[0],
&frame.data[1],
frame.linesize[0] as _,
frame.linesize[1] as _,
bgra,
fmt_data,
i420,
HW_STRIDE_ALIGN,
),
AVPixelFormat::AV_PIX_FMT_YUV420P => {
hw::hw_i420_to_bgra(
hw::hw_i420_to(
fmt,
frame.width as _,
frame.height as _,
&frame.data[0],
@ -260,12 +262,20 @@ impl HwDecoderImage<'_> {
frame.linesize[0] as _,
frame.linesize[1] as _,
frame.linesize[2] as _,
bgra,
fmt_data,
);
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> {

View File

@ -1,5 +1,4 @@
use hbb_common::anyhow::Error;
use hbb_common::{bail, ResultType};
use hbb_common::{log, anyhow::Error, bail, ResultType};
use ndk::media::media_codec::{MediaCodec, MediaCodecDirection, MediaFormat};
use std::ops::Deref;
use std::{
@ -8,9 +7,10 @@ use std::{
time::Duration,
};
use crate::ImageFormat;
use crate::{
codec::{EncoderApi, EncoderCfg},
I420ToARGB,
I420ToABGR, I420ToARGB,
};
/// MediaCodec mime type name
@ -50,7 +50,7 @@ impl MediaCodecDecoder {
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))? {
Some(mut input_buffer) => {
let mut buf = input_buffer.buffer_mut();
@ -83,23 +83,44 @@ impl MediaCodecDecoder {
let bps = 4;
let u = buf.len() * 2 / 3;
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 u_ptr = buf[u..].as_ptr();
let v_ptr = buf[v..].as_ptr();
unsafe {
I420ToARGB(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
rgb.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
match fmt {
ImageFormat::ARGB => {
I420ToARGB(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
raw.as_mut_ptr(),
(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)?;
Ok(true)

View File

@ -43,6 +43,13 @@ pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer
pub mod record;
mod vpx;
#[derive(Copy, Clone)]
pub enum ImageFormat {
Raw,
ABGR,
ARGB,
}
#[inline]
pub fn would_block_if_equal(old: &mut Vec<u8>, b: &[u8]) -> std::io::Result<()> {
// 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::{get_time, ResultType};
use crate::codec::EncoderApi;
use crate::STRIDE_ALIGN;
use crate::{codec::EncoderApi, ImageFormat};
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
use hbb_common::bytes::Bytes;
@ -417,7 +417,7 @@ impl VpxDecoder {
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();
for frame in self.decode(data)? {
drop(img);
@ -431,7 +431,7 @@ impl VpxDecoder {
Ok(Vec::new())
} else {
let mut out = Default::default();
img.rgb(1, rgba, &mut out);
img.to(fmt, 1, &mut out);
Ok(out)
}
}
@ -539,40 +539,60 @@ impl Image {
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 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);
dst.resize(h * w * bps, 0);
let img = self.inner();
unsafe {
if rgba {
super::I420ToARGB(
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 _,
);
} else {
super::I420ToRAW(
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 _,
);
match fmt {
ImageFormat::Raw => {
super::I420ToRAW(
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 _,
);
}
ImageFormat::ARGB => {
super::I420ToARGB(
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 _,
);
}
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},
record::{Recorder, RecorderContext},
VpxDecoderConfig, VpxVideoCodecId,
ImageFormat,
};
use crate::{
@ -943,7 +944,12 @@ impl VideoHandler {
}
match &vf.union {
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 {
self.recorder
.lock()

View File

@ -3,12 +3,21 @@ use crate::{
flutter_ffi::EventToUI,
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;
#[cfg(feature = "flutter_texture_render")]
use hbb_common::libc::c_void;
use hbb_common::{
bail, config::LocalConfig, get_version_number, message_proto::*, rendezvous_proto::ConnType,
ResultType,
bail, config::LocalConfig, get_version_number, log, message_proto::*,
rendezvous_proto::ConnType, ResultType,
};
use serde_json::json;
#[cfg(not(feature = "flutter_texture_render"))]
use std::sync::atomic::{AtomicBool, Ordering};
use std::{
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
}
#[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.
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
#[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.
}
#[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)]
pub struct FlutterHandler {
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,
@ -115,6 +149,84 @@ pub struct FlutterHandler {
// We must check the `rgba_valid` before reading [rgba].
pub rgba: Arc<RwLock<Vec<u8>>>,
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 {
@ -156,6 +268,19 @@ impl FlutterHandler {
}
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 {
@ -315,6 +440,8 @@ impl InvokeUiSession for FlutterHandler {
// unused in flutter
fn adapt_size(&self) {}
#[inline]
#[cfg(not(feature = "flutter_texture_render"))]
fn on_rgba(&self, data: &mut Vec<u8>) {
// If the current rgba is not fetched by flutter, i.e., is valid.
// 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) {
let displays = Self::make_displays_msg(&pi.displays);
let mut features: HashMap<&str, i32> = Default::default();
@ -340,6 +480,7 @@ impl InvokeUiSession for FlutterHandler {
features.insert("privacy_mode", 0);
}
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
*self.peer_info.write().unwrap() = pi.clone();
self.push_event(
"peer_info",
vec![
@ -356,6 +497,7 @@ impl InvokeUiSession for FlutterHandler {
}
fn set_displays(&self, displays: &Vec<DisplayInfo>) {
self.peer_info.write().unwrap().displays = displays.clone();
self.push_event(
"sync_peer_info",
vec![("displays", &Self::make_displays_msg(displays))],
@ -444,6 +586,7 @@ impl InvokeUiSession for FlutterHandler {
#[inline]
fn get_rgba(&self) -> *const u8 {
#[cfg(not(feature = "flutter_texture_render"))]
if self.rgba_valid.load(Ordering::Relaxed) {
return self.rgba.read().unwrap().as_ptr();
}
@ -451,7 +594,8 @@ impl InvokeUiSession for FlutterHandler {
}
#[inline]
fn next_rgba(&mut self) {
fn next_rgba(&self) {
#[cfg(not(feature = "flutter_texture_render"))]
self.rgba_valid.store(false, Ordering::Relaxed);
}
}
@ -517,6 +661,13 @@ pub fn session_add(
/// * `events2ui` - The events channel to ui.
pub fn session_start_(id: &str, event_stream: StreamSink<EventToUI>) -> ResultType<()> {
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);
let session = session.clone();
std::thread::spawn(move || {
@ -711,21 +862,28 @@ pub fn set_cur_session_id(id: String) {
}
#[no_mangle]
#[cfg(not(feature = "flutter_texture_render"))]
pub fn session_get_rgba_size(id: *const char) -> 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) {
if let Some(session) = SESSIONS.read().unwrap().get(id) {
return session.rgba.read().unwrap().len();
}
}
0
}
#[no_mangle]
#[cfg(feature = "flutter_texture_render")]
pub fn session_get_rgba_size(_id: *const char) -> usize {
0
}
#[no_mangle]
pub fn session_get_rgba(id: *const char) -> *const u8 {
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) {
if let Some(session) = SESSIONS.read().unwrap().get(id) {
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) {
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) {
if let Some(session) = SESSIONS.read().unwrap().get(id) {
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> {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
return get_sound_inputs();
@ -1300,6 +1307,17 @@ pub fn main_hide_docker() -> SyncReturn<bool> {
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() {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
crate::flutter::connection_manager::start_listen_ipc_thread();

View File

@ -298,7 +298,7 @@ impl InvokeUiSession for SciterHandler {
std::ptr::null()
}
fn next_rgba(&mut self) {}
fn next_rgba(&self) {}
}
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_incoming(&self);
fn get_rgba(&self) -> *const u8;
fn next_rgba(&mut self);
fn next_rgba(&self);
}
impl<T: InvokeUiSession> Deref for Session<T> {