diff --git a/Cargo.lock b/Cargo.lock index 49d6852..11b36c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -104,6 +119,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -161,15 +191,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -[[package]] -name = "block2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037" -dependencies = [ - "objc2", -] - [[package]] name = "bumpalo" version = "3.17.0" @@ -237,14 +258,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "cgl" -version = "0.3.2" +name = "cidre" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +checksum = "e5b83f5e597a8fb4ba25eec2683aa3e89f9890dd7524622639a38e3f854c60eb" dependencies = [ - "libc", + "cidre-macros", + "half", + "parking_lot", + "tokio", ] +[[package]] +name = "cidre-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f07a383a232853874a9b0b3e80e6eefe9bea73495b8ab4bdd960bc7c1db4c6d" + [[package]] name = "clang-sys" version = "1.8.1" @@ -305,8 +335,8 @@ dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", - "core-foundation 0.9.4", - "core-graphics 0.23.2", + "core-foundation", + "core-graphics", "foreign-types", "libc", "objc", @@ -320,8 +350,8 @@ checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", + "core-foundation", + "core-graphics-types", "libc", "objc", ] @@ -360,26 +390,6 @@ dependencies = [ "futures", ] -[[package]] -name = "core-audio-types" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb31b6a9e9c7cdfbc73bed41f978c41f294e7fc1218f9d74a4bd8901beb87a1" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-audio-types-rs" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f7359c779907f80443d2b2d1b5a61182abb6d8ffd43b6fcb87a27c327d845f" -dependencies = [ - "core-foundation 0.10.0", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -390,16 +400,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -413,21 +413,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", + "core-foundation", + "core-graphics-types", "foreign-types", "libc", ] @@ -439,8 +426,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32eb7c354ae9f6d437a6039099ce7ecd049337a8109b23d73e48e8ffba8e9cd5" dependencies = [ "bitflags 2.6.0", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", + "core-foundation", + "core-graphics-types", "foreign-types", "libc", ] @@ -452,98 +439,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "libc", ] -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.10.0", - "libc", -] - -[[package]] -name = "core-graphics2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4583956b9806b69f73fcb23aee05eb3620efc282972f08f6a6db7504f8334d" -dependencies = [ - "bitflags 2.6.0", - "block", - "cfg-if", - "core-foundation 0.10.0", - "libc", -] - -[[package]] -name = "core-media" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "735c25a66449364e6850ac0e27e45d5b13c6e6fe6f44a2f96cbff2d9d29447e3" -dependencies = [ - "block", - "cfg-if", - "core-audio-types", - "core-foundation 0.10.0", - "core-graphics2", - "core-video", - "libc", -] - -[[package]] -name = "core-media-rs" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e33a8804301de5fc0f705ea1cdea692233c08bdcee8e42abb258f5de3b9a5e7" -dependencies = [ - "core-audio-types-rs", - "core-foundation 0.10.0", - "core-utils-rs", - "core-video-rs", - "thiserror 2.0.12", -] - -[[package]] -name = "core-utils-rs" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068ec1aa07335261033bf610b2868ea9db05353468b72b0045ae469e00d26121" -dependencies = [ - "core-foundation 0.10.0", - "four-char-code", -] - -[[package]] -name = "core-video" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45e71d5be22206bed53c3c3cb99315fc4c3d31b8963808c6bc4538168c4f8ef" -dependencies = [ - "block", - "core-foundation 0.10.0", - "core-graphics2", - "io-surface", - "libc", -] - -[[package]] -name = "core-video-rs" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7559e93f816c05607068cb0b741d997a47709f4ba70b36a02d335f7136b30c46" -dependencies = [ - "core-foundation 0.10.0", - "core-graphics 0.24.0", - "core-utils-rs", - "io-surface", - "thiserror 2.0.12", -] - [[package]] name = "coreaudio-rs" version = "0.11.3" @@ -612,6 +511,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "ctrlc" version = "3.4.6" @@ -639,12 +544,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - [[package]] name = "either" version = "1.13.0" @@ -684,17 +583,11 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" -[[package]] -name = "four-char-code" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42da99970737c0150e3c5cd1cdc510735a2511739f5c3aa3c6bfc9f31441488d" - [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -707,9 +600,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -717,15 +610,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -734,15 +627,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -751,21 +644,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -790,12 +683,28 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -808,6 +717,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "indexmap" version = "2.5.0" @@ -819,15 +734,13 @@ dependencies = [ ] [[package]] -name = "io-surface" -version = "0.16.0" +name = "io-uring" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8283575d5f0b2e7447ec0840363879d71c0fa325d4c699d5b45208ea4a51f45e" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" dependencies = [ - "cgl", - "core-foundation 0.10.0", - "core-foundation-sys", - "leaky-cow", + "bitflags 2.6.0", + "cfg-if", "libc", ] @@ -899,26 +812,11 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -[[package]] -name = "leak" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73" - -[[package]] -name = "leaky-cow" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc" -dependencies = [ - "leak", -] - [[package]] name = "libc" -version = "0.2.158" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libdbus-sys" @@ -1013,6 +911,27 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "ndk" version = "0.8.0" @@ -1132,31 +1051,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", ] [[package]] -name = "objc2" -version = "0.6.0" +name = "object" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ - "objc2-encode", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", + "memchr", ] [[package]] @@ -1381,6 +1284,12 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "rustc-demangle" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1406,20 +1315,17 @@ dependencies = [ name = "scap" version = "0.0.8" dependencies = [ + "cidre", "cocoa", - "core-foundation 0.10.0", - "core-graphics 0.24.0", "core-graphics-helmer-fork", - "core-media", - "core-media-rs", "cpal", "dbus", + "futures", "objc", "pipewire", "rand", - "screencapturekit", "sysinfo", - "tao-core-video-sys", + "thiserror 2.0.12", "windows 0.58.0", "windows-capture", ] @@ -1430,22 +1336,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "screencapturekit" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd797e2f07759d67fc00c3085c55dae07c37e73dba29dc1159484cbb2946bd6f" -dependencies = [ - "block2", - "core-foundation 0.10.0", - "core-graphics 0.24.0", - "core-media-rs", - "core-utils-rs", - "core-video-rs", - "dispatch", - "objc", -] - [[package]] name = "serde" version = "1.0.210" @@ -1481,6 +1371,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1496,6 +1395,16 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1541,18 +1450,6 @@ dependencies = [ "version-compare", ] -[[package]] -name = "tao-core-video-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271450eb289cb4d8d0720c6ce70c72c8c858c93dd61fc625881616752e6b98f6" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "objc", -] - [[package]] name = "target-lexicon" version = "0.12.16" @@ -1599,6 +1496,36 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio" +version = "1.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.8.19" @@ -1926,6 +1853,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index e6ffa00..b3f4d24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "scap" description = "Modern, high-performance screen capture library for Rust. Cross-platform." version = "0.0.8" edition = "2021" -rust-version = "1.71" +rust-version = "1.85" license = "MIT" authors = [ "Siddharth ", @@ -16,7 +16,9 @@ keywords = ["screen", "recording", "video", "capture", "media"] categories = ["graphics", "multimedia", "multimedia::video"] [dependencies] +futures = "0.3.31" sysinfo = "0.30.0" +thiserror = "2.0.12" [target.'cfg(target_os = "windows")'.dependencies] windows-capture = "1.4.2" @@ -30,15 +32,10 @@ windows = { version = "0.58", features = [ cpal = "0.15.3" [target.'cfg(target_os = "macos")'.dependencies] -tao-core-video-sys = "0.2.0" core-graphics-helmer-fork = "0.24.0" -screencapturekit = "0.3.2" cocoa = "0.25.0" objc = "0.2.7" -core-foundation = "0.10.0" -core-graphics = "0.24.0" -core-media-rs = "0.3.4" -core-media = "0.5.1" +cidre = "0.9.2" [target.'cfg(target_os = "linux")'.dependencies] pipewire = "0.8.0" diff --git a/src/capturer/engine/mac/apple_sys.rs b/src/capturer/engine/mac/apple_sys.rs deleted file mode 100644 index 33b1874..0000000 --- a/src/capturer/engine/mac/apple_sys.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![allow(non_upper_case_globals)] - -// use core_media_rs::cm_time::CMTime; - -use core_media::time::CMTime; - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __CFDictionary { - _unused: [u8; 0], -} - -pub type CFDictionaryRef = *const __CFDictionary; -pub type CFTypeRef = *const ::std::os::raw::c_void; -pub type CFIndex = ::std::os::raw::c_long; -pub type CFNumberType = CFIndex; -pub type Boolean = ::std::os::raw::c_uchar; - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __CFNumber { - _unused: [u8; 0], -} - -#[allow(non_camel_case_types)] -pub type id = *mut objc::runtime::Object; - -#[repr(transparent)] -#[derive(Debug, Copy, Clone)] -pub struct NSString(pub id); - -pub type CFNumberRef = *const __CFNumber; -pub type SCStreamFrameInfo = NSString; -extern "C" { - pub fn CFDictionaryGetValue( - theDict: CFDictionaryRef, - key: *const ::std::os::raw::c_void, - ) -> *const ::std::os::raw::c_void; - pub fn CFNumberGetValue( - number: CFNumberRef, - theType: CFNumberType, - valuePtr: *mut ::std::os::raw::c_void, - ) -> Boolean; - pub fn CMTimeGetSeconds(time: CMTime) -> f64; - pub static SCStreamFrameInfoStatus: SCStreamFrameInfo; -} -pub const CFNumberType_kCFNumberSInt64Type: CFNumberType = 4; -pub type NSInteger = ::std::os::raw::c_long; -pub type SCFrameStatus = NSInteger; -pub const SCFrameStatus_SCFrameStatusComplete: SCFrameStatus = 0; diff --git a/src/capturer/engine/mac/ext.rs b/src/capturer/engine/mac/ext.rs new file mode 100644 index 0000000..03a4cee --- /dev/null +++ b/src/capturer/engine/mac/ext.rs @@ -0,0 +1,13 @@ +use cidre::cg; +use core_graphics_helmer_fork::display::{CGDisplay, CGDisplayMode}; + +pub trait DirectDisplayIdExt { + fn display_mode(&self) -> Option; +} + +impl DirectDisplayIdExt for cg::DirectDisplayId { + #[inline] + fn display_mode(&self) -> Option { + CGDisplay::new(self.0).display_mode() + } +} diff --git a/src/capturer/engine/mac/mod.rs b/src/capturer/engine/mac/mod.rs index c5bd75a..3136a3e 100644 --- a/src/capturer/engine/mac/mod.rs +++ b/src/capturer/engine/mac/mod.rs @@ -1,30 +1,14 @@ use std::sync::atomic::AtomicBool; use std::sync::mpsc; -use std::time::Duration; use std::{cmp, sync::Arc}; -use core_foundation::error::CFError; -use core_graphics::display::{CGPoint, CGRect, CGSize}; -use core_media::sync::{CMClock, CMClockGetHostTimeClock}; -use core_media::time::{CMTime, CMTimeSubtract}; -// use core_media_rs::cm_time::CMTime; -use pixel_buffer::get_sample_buffer_pts; -use pixelformat::get_pts_in_nanoseconds; -use screencapturekit::{ - output::{ - sc_stream_frame_info::{SCFrameStatus, SCStreamFrameInfo}, - CMSampleBuffer, - }, - shareable_content::SCShareableContent, - stream::{ - configuration::{pixel_format::PixelFormat, SCStreamConfiguration}, - content_filter::SCContentFilter, - delegate_trait::SCStreamDelegateTrait, - output_trait::SCStreamOutputTrait, - output_type::SCStreamOutputType, - SCStream, - }, +use cidre::mach; +use cidre::sc::StreamDelegateImpl; +use cidre::{ + arc, cg, cm, cv, define_obj_type, dispatch, ns, objc, + sc::{self, StreamDelegate, StreamOutput, StreamOutputImpl}, }; +use futures::executor::block_on; use crate::frame::{AudioFormat, AudioFrame, Frame, FrameType, VideoFrame}; use crate::targets::Target; @@ -36,77 +20,111 @@ use crate::{ use super::ChannelItem; -mod apple_sys; +pub(crate) mod ext; mod pixel_buffer; mod pixelformat; -struct ErrorHandler { +struct ErrorHandlerInner { error_flag: Arc, } -impl SCStreamDelegateTrait for ErrorHandler { - fn did_stop_with_error(&self, _stream: SCStream, _error: CFError) { +define_obj_type!( + pub ErrorHandler + StreamDelegateImpl, + ErrorHandlerInner, + ERROR_HANDLER +); + +impl sc::stream::Delegate for ErrorHandler {} + +#[objc::add_methods] +impl sc::stream::DelegateImpl for ErrorHandler { + extern "C" fn impl_stream_did_stop_with_err( + &mut self, + _cmd: Option<&objc::Sel>, + stream: &sc::Stream, + error: &ns::Error, + ) { eprintln!("Screen capture error occurred."); - self.error_flag + self.inner_mut() + .error_flag .store(true, std::sync::atomic::Ordering::Relaxed); } } -#[derive(Clone)] -pub struct Capturer { +#[repr(C)] +pub struct CapturerInner { pub tx: mpsc::Sender, } -impl Capturer { - pub fn new(tx: mpsc::Sender) -> Self { - Capturer { tx } +define_obj_type!(pub Capturer + StreamOutputImpl, CapturerInner, CAPTURER); + +impl sc::stream::Output for Capturer {} + +#[objc::add_methods] +impl sc::stream::OutputImpl for Capturer { + extern "C" fn impl_stream_did_output_sample_buf( + &mut self, + _cmd: Option<&objc::Sel>, + _stream: &sc::Stream, + sample_buf: &mut cm::SampleBuf, + kind: sc::OutputType, + ) { + let _ = self.inner_mut().tx.send((sample_buf.retained(), kind)); } } -impl SCStreamOutputTrait for Capturer { - fn did_output_sample_buffer(&self, sample: CMSampleBuffer, of_type: SCStreamOutputType) { - self.tx.send((sample, of_type)).unwrap_or(()); - } +#[derive(thiserror::Error, Debug)] +pub(crate) enum CreateCapturerError { + #[error("{0}")] + OtherNative(#[from] arc::R), + #[error("Window with title '{0}' not found")] + WindowNotFound(String), + #[error("Display with title '{0}' not found")] + DisplayNotFound(String), } -pub fn create_capturer( +pub(crate) fn create_capturer( options: &Options, tx: mpsc::Sender, error_flag: Arc, -) -> Result { +) -> Result<(arc::R, arc::R, arc::R), CreateCapturerError> { // If no target is specified, capture the main display let target = options .target .clone() .unwrap_or_else(|| Target::Display(targets::get_main_display())); - let sc_shareable_content = SCShareableContent::get().unwrap(); + let shareable_content = block_on(sc::ShareableContent::current())?; let filter = match target { Target::Window(window) => { + let windows = shareable_content.windows(); + // Get SCWindow from window id - let sc_window = sc_shareable_content - .windows() - .into_iter() - .find(|sc_win| sc_win.window_id() == window.id) - .unwrap(); + let sc_window = windows + .iter() + .find(|sc_win| sc_win.id() == window.id) + .ok_or_else(|| CreateCapturerError::WindowNotFound(window.title))?; // Return a DesktopIndependentWindow // https://developer.apple.com/documentation/screencapturekit/sccontentfilter/3919804-init - SCContentFilter::new().with_desktop_independent_window(&sc_window) + sc::ContentFilter::with_desktop_independent_window(sc_window) } Target::Display(display) => { + let displays = shareable_content.displays(); // Get SCDisplay from display id - let sc_display = sc_shareable_content - .displays() - .into_iter() - .find(|sc_dis| sc_dis.display_id() == display.id) - .unwrap(); + let sc_display = displays + .iter() + .find(|sc_dis| sc_dis.display_id() == display.raw_handle) + .ok_or_else(|| CreateCapturerError::DisplayNotFound(display.title))?; match &options.excluded_targets { - None => SCContentFilter::new().with_display_excluding_windows(&sc_display, &[]), + None => sc::ContentFilter::with_display_excluding_windows( + &sc_display, + &ns::Array::new(), + ), Some(excluded_targets) => { - let windows = sc_shareable_content.windows(); + let windows = shareable_content.windows(); let excluded_windows = windows .iter() .filter(|window| { @@ -114,15 +132,17 @@ pub fn create_capturer( .iter() .any(|excluded_target| match excluded_target { Target::Window(excluded_window) => { - excluded_window.id == window.window_id() + excluded_window.id == window.id() } _ => false, }) }) .collect::>(); - SCContentFilter::new() - .with_display_excluding_windows(&sc_display, excluded_windows.as_slice()) + sc::ContentFilter::with_display_excluding_windows( + &sc_display, + &ns::Array::from_slice(&excluded_windows), + ) } } } @@ -130,52 +150,60 @@ pub fn create_capturer( let crop_area = get_crop_area(options); - let source_rect = CGRect { - origin: CGPoint { + let source_rect = cg::Rect { + origin: cg::Point { x: crop_area.origin.x, y: crop_area.origin.y, }, - size: CGSize { + size: cg::Size { width: crop_area.size.width, height: crop_area.size.height, }, }; let pixel_format = match options.output_type { - FrameType::YUVFrame => PixelFormat::YCbCr_420v, - FrameType::BGR0 => PixelFormat::BGRA, - FrameType::RGB => PixelFormat::BGRA, - FrameType::BGRAFrame => PixelFormat::BGRA, + FrameType::YUVFrame => cv::PixelFormat::_420V, + FrameType::BGR0 => cv::PixelFormat::_32_BGRA, + FrameType::RGB => cv::PixelFormat::_32_BGRA, + FrameType::BGRAFrame => cv::PixelFormat::_32_BGRA, }; let [width, height] = get_output_frame_size(options); - let stream_config = SCStreamConfiguration::new() - .set_width(width)? - .set_height(height)? - .set_source_rect(source_rect)? - .set_pixel_format(pixel_format)? - .set_shows_cursor(options.show_cursor)? - .set_minimum_frame_interval(&core_media_rs::cm_time::CMTime { - value: 1, - timescale: options.fps as i32, - epoch: 0, - flags: 1, - })? - .set_captures_audio(options.captures_audio)?; - - let mut stream = - SCStream::new_with_delegate(&filter, &stream_config, ErrorHandler { error_flag }); - - let capturer = Capturer::new(tx); + let mut stream_config = sc::StreamCfg::new(); + stream_config.set_width(width as usize); + stream_config.set_height(height as usize); + stream_config.set_src_rect(source_rect); + stream_config.set_pixel_format(pixel_format); + stream_config.set_shows_cursor(options.show_cursor); + stream_config.set_minimum_frame_interval(cm::Time { + value: 1, + scale: options.fps as i32, + epoch: 0, + flags: cm::TimeFlags::VALID, + }); + stream_config.set_captures_audio(options.captures_audio); + + let error_handler = ErrorHandler::with(ErrorHandlerInner { error_flag }); + let stream = sc::Stream::with_delegate(&filter, &stream_config, error_handler.as_ref()); + + let capturer = CapturerInner { tx }; + + let queue = dispatch::Queue::serial_with_ar_pool(); + + let capturer = Capturer::with(capturer); if options.captures_audio { - stream.add_output_handler(capturer.clone(), SCStreamOutputType::Audio); + stream + .add_stream_output(capturer.as_ref(), sc::OutputType::Audio, Some(&queue)) + .unwrap(); } - stream.add_output_handler(capturer, SCStreamOutputType::Screen); + stream + .add_stream_output(capturer.as_ref(), sc::OutputType::Screen, Some(&queue)) + .unwrap(); - Ok(stream) + Ok((capturer, error_handler, stream)) } pub fn get_output_frame_size(options: &Options) -> [u32; 2] { @@ -246,55 +274,79 @@ pub fn get_crop_area(options: &Options) -> Area { } pub fn process_sample_buffer( - sample: CMSampleBuffer, - of_type: SCStreamOutputType, + mut sample: arc::R, + of_type: sc::stream::OutputType, output_type: FrameType, ) -> Option { let system_time = std::time::SystemTime::now(); + let system_mach_time = mach::abs_time(); - let clock = CMClock::get_host_time_clock(); - let time = clock.get_time(); - // get_host_time_clock should return a static ref, not an owned instance - std::mem::forget(clock); + let frame_cm_time = sample.pts(); + let frame_mach_time = cm::Clock::convert_host_time_to_sys_units(frame_cm_time); - let gap = time.subtract(get_sample_buffer_pts(&sample)); - let gap_f = gap.value as f64 / gap.timescale as f64; + let mach_time_diff = if frame_mach_time > system_mach_time { + (frame_mach_time - system_mach_time) as i64 + } else { + -((system_mach_time - frame_mach_time) as i64) + }; - let time = system_time - .checked_sub(Duration::from_secs_f64(gap_f)) - .unwrap(); + // Convert mach time difference to nanoseconds + let mach_timebase = mach::TimeBaseInfo::new(); + let nanos_diff = (mach_time_diff * mach_timebase.numer as i64) / mach_timebase.denom as i64; - match of_type { - SCStreamOutputType::Screen => { - let info = SCStreamFrameInfo::from_sample_buffer(&sample).unwrap(); - let frame_status = info.status(); + // Calculate frame SystemTime + let frame_system_time = if nanos_diff >= 0 { + system_time + std::time::Duration::from_nanos(nanos_diff as u64) + } else { + system_time - std::time::Duration::from_nanos((-nanos_diff) as u64) + }; - match frame_status { - SCFrameStatus::Complete | SCFrameStatus::Started => unsafe { + match of_type { + sc::stream::OutputType::Screen => { + let attaches = sample.attaches(false).and_then(|a| { + let mut iter = a.iter(); + iter.next() + })?; + + match attaches + .get(sc::FrameInfo::status().as_cf())? + .as_number() + .to_i32() + .unwrap() + { + 0 => unsafe { return Some(Frame::Video(match output_type { FrameType::YUVFrame => { - let yuvframe = pixelformat::create_yuv_frame(sample, time).unwrap(); + let yuvframe = + pixelformat::create_yuv_frame(sample.as_mut(), frame_system_time) + .unwrap(); VideoFrame::YUVFrame(yuvframe) } FrameType::RGB => { - let rgbframe = pixelformat::create_rgb_frame(sample, time).unwrap(); + let rgbframe = + pixelformat::create_rgb_frame(sample.as_mut(), frame_system_time) + .unwrap(); VideoFrame::RGB(rgbframe) } FrameType::BGR0 => { - let bgrframe = pixelformat::create_bgr_frame(sample, time).unwrap(); + let bgrframe = + pixelformat::create_bgr_frame(sample.as_mut(), frame_system_time) + .unwrap(); VideoFrame::BGR0(bgrframe) } FrameType::BGRAFrame => { - let bgraframe = pixelformat::create_bgra_frame(sample, time).unwrap(); + let bgraframe = + pixelformat::create_bgra_frame(sample.as_mut(), frame_system_time) + .unwrap(); VideoFrame::BGRA(bgraframe) } })); }, - SCFrameStatus::Idle => { + 1 => { // Quick hack - just send an empty frame, and the caller can figure out how to handle it if let FrameType::BGRAFrame = output_type { return Some(Frame::Video(VideoFrame::BGRA(BGRAFrame { - display_time: time, + display_time: frame_system_time, width: 0, height: 0, data: vec![], @@ -302,14 +354,18 @@ pub fn process_sample_buffer( } } _ => {} - } + }; + + None } - SCStreamOutputType::Audio => { - let list = sample.get_audio_buffer_list().unwrap(); + sc::stream::OutputType::Audio => { + let list = sample.audio_buf_list::<2>().ok()?; let mut bytes = Vec::::new(); - for buffer in list.buffers() { - bytes.extend(buffer.data()); + for buffer in list.list().buffers { + bytes.extend(unsafe { + std::slice::from_raw_parts(buffer.data, buffer.data_bytes_size as usize) + }); } return Some(Frame::Audio(AudioFrame::new( @@ -317,12 +373,11 @@ pub fn process_sample_buffer( 2, false, bytes, - sample.get_num_samples() as usize, + sample.num_samples() as usize, 48_000, - time, + frame_system_time, ))); } - }; - - None + _ => None, + } } diff --git a/src/capturer/engine/mac/pixel_buffer.rs b/src/capturer/engine/mac/pixel_buffer.rs index 7e307b2..32a1feb 100644 --- a/src/capturer/engine/mac/pixel_buffer.rs +++ b/src/capturer/engine/mac/pixel_buffer.rs @@ -1,10 +1,4 @@ -use core_foundation::base::TCFType; -use core_media::time::CMTime; -// use core_media_rs::cm_time::CMTime; -use screencapturekit::{ - output::{CMSampleBuffer, CMSampleBufferRef}, - stream::output_type::SCStreamOutputType, -}; +use cidre::{arc, cm, sc}; use std::sync::mpsc; use crate::capturer::RawCapturer; @@ -12,7 +6,7 @@ use crate::capturer::RawCapturer; impl RawCapturer<'_> { pub fn get_next_sample_buffer( &self, - ) -> Result<(CMSampleBuffer, SCStreamOutputType), mpsc::RecvError> { + ) -> Result<(arc::R, sc::stream::OutputType), mpsc::RecvError> { use std::time::Duration; let capturer = &self.capturer; @@ -34,12 +28,3 @@ impl RawCapturer<'_> { } } } - -pub fn get_sample_buffer_pts(sample_buffer: &CMSampleBuffer) -> CMTime { - extern "C" { - pub fn CMSampleBufferGetPresentationTimeStamp(sample: CMSampleBufferRef) -> CMTime; - - } - - unsafe { CMSampleBufferGetPresentationTimeStamp(sample_buffer.as_concrete_TypeRef()) } -} diff --git a/src/capturer/engine/mac/pixelformat.rs b/src/capturer/engine/mac/pixelformat.rs index 863caf5..fd9047a 100644 --- a/src/capturer/engine/mac/pixelformat.rs +++ b/src/capturer/engine/mac/pixelformat.rs @@ -1,51 +1,58 @@ use std::time::SystemTime; -use screencapturekit::output::{ - sc_stream_frame_info::{SCFrameStatus, SCStreamFrameInfo}, - CMSampleBuffer, LockTrait, -}; +use cidre::{cm, cv}; -use super::{apple_sys::CMTimeGetSeconds, pixel_buffer::get_sample_buffer_pts}; use crate::frame::{ convert_bgra_to_rgb, get_cropped_data, remove_alpha_channel, BGRAFrame, BGRFrame, RGBFrame, YUVFrame, }; -// Returns a frame's presentation timestamp in nanoseconds since an arbitrary start time. -// This is typically yielded from a monotonic clock started on system boot. -pub fn get_pts_in_nanoseconds(sample_buffer: &CMSampleBuffer) -> u64 { - let pts = get_sample_buffer_pts(sample_buffer); - - let seconds = unsafe { CMTimeGetSeconds(pts) }; - - (seconds * 1_000_000_000.).trunc() as u64 -} - pub unsafe fn create_yuv_frame( - sample_buffer: CMSampleBuffer, + sample_buffer: &mut cm::SampleBuf, display_time: SystemTime, ) -> Option { - let info = SCStreamFrameInfo::from_sample_buffer(&sample_buffer).unwrap(); - let status = info.status(); - if !matches!(status, SCFrameStatus::Complete) { - return None; - } + let image_buffer = sample_buffer.image_buf_mut().unwrap(); - let pixel_buffer = sample_buffer.get_pixel_buffer().unwrap(); - let bytes = pixel_buffer.lock().unwrap(); - let width = pixel_buffer.get_width(); - let height = pixel_buffer.get_height(); + unsafe { + image_buffer + .lock_base_addr(cv::pixel_buffer::LockFlags::DEFAULT) + .result() + .unwrap() + }; + + let width = image_buffer.width(); + let height = image_buffer.height(); if width == 0 || height == 0 { return None; } - let luminance_bytes = bytes.as_slice_plane(0).to_vec(); - let luminance_stride = pixel_buffer.get_bytes_per_row_of_plane(0); - let chrominance_bytes = bytes.as_slice_plane(1).to_vec(); - let chrominance_stride = pixel_buffer.get_bytes_per_row_of_plane(1); + let luminance_stride = image_buffer.plane_bytes_per_row(0); + let luminance_bytes = unsafe { + std::slice::from_raw_parts( + image_buffer.plane_base_address(0), + luminance_stride * image_buffer.plane_height(0), + ) + } + .to_vec(); + + let chrominance_stride = image_buffer.plane_bytes_per_row(0); + let chrominance_bytes = unsafe { + std::slice::from_raw_parts( + image_buffer.plane_base_address(0), + luminance_stride * image_buffer.plane_height(0), + ) + } + .to_vec(); + + unsafe { + image_buffer + .unlock_lock_base_addr(cv::pixel_buffer::LockFlags::DEFAULT) + .result() + .unwrap() + }; - YUVFrame { + Some(YUVFrame { display_time, width: width as i32, height: height as i32, @@ -53,32 +60,39 @@ pub unsafe fn create_yuv_frame( luminance_stride: luminance_stride as i32, chrominance_bytes, chrominance_stride: chrominance_stride as i32, - } - .into() + }) } pub unsafe fn create_bgr_frame( - sample_buffer: CMSampleBuffer, + sample_buffer: &mut cm::SampleBuf, display_time: SystemTime, ) -> Option { - let pixel_buffer = sample_buffer.get_pixel_buffer().unwrap(); - let bytes = pixel_buffer.lock().unwrap(); - let width = pixel_buffer.get_width(); - let height = pixel_buffer.get_height(); + let image_buffer = sample_buffer.image_buf_mut().unwrap(); + + unsafe { + image_buffer + .lock_base_addr(cv::pixel_buffer::LockFlags::DEFAULT) + .result() + .unwrap() + }; + + let width = image_buffer.width(); + let height = image_buffer.height(); if width == 0 || height == 0 { return None; } - let bytes_per_row = pixel_buffer.get_bytes_per_row(); - let data = bytes.to_vec(); + let stride = image_buffer.plane_bytes_per_row(0); + let bytes = unsafe { + std::slice::from_raw_parts( + image_buffer.plane_base_address(0), + stride * image_buffer.plane_height(0), + ) + } + .to_vec(); - let cropped_data = get_cropped_data( - data, - (bytes_per_row / 4) as i32, - height as i32, - width as i32, - ); + let cropped_data = get_cropped_data(bytes, (stride / 4) as i32, height as i32, width as i32); Some(BGRFrame { display_time, @@ -89,24 +103,38 @@ pub unsafe fn create_bgr_frame( } pub unsafe fn create_bgra_frame( - sample_buffer: CMSampleBuffer, + sample_buffer: &mut cm::SampleBuf, display_time: SystemTime, ) -> Option { - let pixel_buffer = sample_buffer.get_pixel_buffer().unwrap(); - let bytes = pixel_buffer.lock().unwrap(); - let width = pixel_buffer.get_width(); - let height = pixel_buffer.get_height(); + let image_buffer = sample_buffer.image_buf_mut().unwrap(); + + unsafe { + image_buffer + .lock_base_addr(cv::pixel_buffer::LockFlags::DEFAULT) + .result() + .unwrap() + }; + + let width = image_buffer.width(); + let height = image_buffer.height(); if width == 0 || height == 0 { return None; } - let bytes_per_row = pixel_buffer.get_bytes_per_row(); + let stride = image_buffer.plane_bytes_per_row(0); let mut data: Vec = vec![]; + let bytes = unsafe { + std::slice::from_raw_parts( + image_buffer.plane_base_address(0), + stride * image_buffer.plane_height(0), + ) + }; + for i in 0..height { - let base = i * bytes_per_row; + let base = i * stride; data.extend_from_slice(&bytes[base as usize..(base + 4 * width) as usize]); } @@ -119,27 +147,36 @@ pub unsafe fn create_bgra_frame( } pub unsafe fn create_rgb_frame( - sample_buffer: CMSampleBuffer, + sample_buffer: &mut cm::SampleBuf, display_time: SystemTime, ) -> Option { - let pixel_buffer = sample_buffer.get_pixel_buffer().unwrap(); - let bytes = pixel_buffer.lock().unwrap(); - let width = pixel_buffer.get_width(); - let height = pixel_buffer.get_height(); + let image_buffer = sample_buffer.image_buf_mut().unwrap(); + + unsafe { + image_buffer + .lock_base_addr(cv::pixel_buffer::LockFlags::DEFAULT) + .result() + .unwrap() + }; + + let width = image_buffer.width(); + let height = image_buffer.height(); if width == 0 || height == 0 { return None; } - let bytes_per_row = pixel_buffer.get_bytes_per_row(); - let data = bytes.to_vec(); + let stride = image_buffer.plane_bytes_per_row(0); - let cropped_data = get_cropped_data( - data, - (bytes_per_row / 4) as i32, - height as i32, - width as i32, - ); + let bytes = unsafe { + std::slice::from_raw_parts( + image_buffer.plane_base_address(0), + stride * image_buffer.plane_height(0), + ) + } + .to_vec(); + + let cropped_data = get_cropped_data(bytes, (stride / 4) as i32, height as i32, width as i32); Some(RGBFrame { display_time, diff --git a/src/capturer/engine/mod.rs b/src/capturer/engine/mod.rs index edaf712..e8aa3a0 100644 --- a/src/capturer/engine/mod.rs +++ b/src/capturer/engine/mod.rs @@ -14,8 +14,8 @@ mod linux; #[cfg(target_os = "macos")] pub type ChannelItem = ( - screencapturekit::output::CMSampleBuffer, - screencapturekit::stream::output_type::SCStreamOutputType, + cidre::arc::R, + cidre::sc::stream::OutputType, ); #[cfg(not(target_os = "macos"))] pub type ChannelItem = Frame; @@ -42,7 +42,11 @@ pub struct Engine { options: Options, #[cfg(target_os = "macos")] - mac: screencapturekit::stream::SCStream, + mac: ( + cidre::arc::R, + cidre::arc::R, + cidre::arc::R, + ), #[cfg(target_os = "macos")] error_flag: std::sync::Arc, @@ -89,8 +93,9 @@ impl Engine { pub fn start(&mut self) { #[cfg(target_os = "macos")] { - // self.mac.add_output(Capturer::new(tx)); - self.mac.start_capture().expect("Failed to start capture"); + use futures::executor::block_on; + + block_on(self.mac.2.start()).expect("Failed to start capture"); } #[cfg(target_os = "windows")] @@ -107,7 +112,9 @@ impl Engine { pub fn stop(&mut self) { #[cfg(target_os = "macos")] { - self.mac.stop_capture().expect("Failed to stop capture"); + use futures::executor::block_on; + + block_on(self.mac.2.stop()).expect("Failed to stop capture"); } #[cfg(target_os = "windows")] diff --git a/src/capturer/mod.rs b/src/capturer/mod.rs index d2103f9..04a189b 100644 --- a/src/capturer/mod.rs +++ b/src/capturer/mod.rs @@ -101,18 +101,6 @@ impl std::fmt::Display for CapturerBuildError { impl Error for CapturerBuildError {} impl Capturer { - /// Create a new capturer instance with the provided options - #[deprecated( - since = "0.0.6", - note = "Use `build` instead of `new` to create a new capturer instance." - )] - pub fn new(options: Options) -> Capturer { - let (tx, rx) = mpsc::channel(); - let engine = engine::Engine::new(&options, tx); - - Capturer { engine, rx } - } - /// Build a new [Capturer] instance with the provided options pub fn build(options: Options) -> Result { if !is_supported() { diff --git a/src/main.rs b/src/main.rs index 3e1b38a..9f612ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use scap::{ capturer::{Area, Capturer, Options, Point, Size}, frame::{Frame, VideoFrame}, }; -use std::{process, time::SystemTime}; +use std::process; fn main() { // Check if the platform is supported @@ -56,7 +56,6 @@ fn main() { recorder.start_capture(); // Capture 100 frames - let mut start_time = SystemTime::now(); for i in 0..100 { let frame = loop { match recorder.get_next_frame().expect("Error") { diff --git a/src/targets/mac/mod.rs b/src/targets/mac/mod.rs index 7317206..f4f1b97 100644 --- a/src/targets/mac/mod.rs +++ b/src/targets/mac/mod.rs @@ -1,14 +1,15 @@ +use cidre::{cg, ns, sc}; use cocoa::appkit::{NSApp, NSScreen}; use cocoa::base::{id, nil}; use cocoa::foundation::{NSRect, NSString, NSUInteger}; -use core_graphics_helmer_fork::display::{CGDirectDisplayID, CGDisplay, CGMainDisplayID}; -use core_graphics_helmer_fork::window::CGWindowID; +use futures::executor::block_on; use objc::{msg_send, sel, sel_impl}; -use screencapturekit::shareable_content::SCShareableContent; + +use crate::engine::mac::ext::DirectDisplayIdExt; use super::{Display, Target}; -fn get_display_name(display_id: CGDirectDisplayID) -> String { +fn get_display_name(display_id: cg::DirectDisplayId) -> String { unsafe { // Get all screens let screens: id = NSScreen::screens(nil); @@ -20,7 +21,7 @@ fn get_display_name(display_id: CGDirectDisplayID) -> String { let display_id_number: id = msg_send![device_description, objectForKey: NSString::alloc(nil).init_str("NSScreenNumber")]; let display_id_number: u32 = msg_send![display_id_number, unsignedIntValue]; - if display_id_number == display_id { + if display_id_number == display_id.0 { let localized_name: id = msg_send![screen, localizedName]; let name: *const i8 = msg_send![localized_name, UTF8String]; return std::ffi::CStr::from_ptr(name) @@ -29,40 +30,39 @@ fn get_display_name(display_id: CGDirectDisplayID) -> String { } } - format!("Unknown Display {}", display_id) + format!("Unknown Display {}", display_id.0) } } pub fn get_all_targets() -> Vec { let mut targets: Vec = Vec::new(); - let content = SCShareableContent::get().unwrap(); + let content = block_on(sc::ShareableContent::current()).unwrap(); // Add displays to targets - for display in content.displays() { - let id: CGDirectDisplayID = display.display_id(); - let raw_handle = CGDisplay::new(id); + for display in content.displays().iter() { + let id = display.display_id(); + let title = get_display_name(id); let target = Target::Display(super::Display { - id, + id: id.0, title, - raw_handle, + raw_handle: id, }); targets.push(target); } // Add windows to targets - for window in content.windows() { - let id = window.window_id(); + for window in content.windows().iter() { + let id = window.id(); let title = window.title(); - let raw_handle: CGWindowID = id; let target = Target::Window(super::Window { id, - title, - raw_handle, + title: title.map(|v| v.to_string()).unwrap_or_default(), + raw_handle: id, }); targets.push(target); } @@ -71,13 +71,13 @@ pub fn get_all_targets() -> Vec { } pub fn get_main_display() -> Display { - let id = unsafe { CGMainDisplayID() }; + let id = cg::direct_display::Id::main(); let title = get_display_name(id); Display { - id, + id: id.0, title, - raw_handle: CGDisplay::new(id), + raw_handle: id, } } diff --git a/src/targets/mod.rs b/src/targets/mod.rs index 930ab62..c19b00c 100644 --- a/src/targets/mod.rs +++ b/src/targets/mod.rs @@ -1,3 +1,6 @@ +#[cfg(target_os = "macos")] +use futures::executor::block_on; + #[cfg(target_os = "macos")] mod mac; @@ -16,7 +19,7 @@ pub struct Window { pub raw_handle: windows::Win32::Foundation::HWND, #[cfg(target_os = "macos")] - pub raw_handle: core_graphics_helmer_fork::window::CGWindowID, + pub raw_handle: cidre::cg::WindowId, } #[derive(Debug, Clone)] @@ -28,7 +31,7 @@ pub struct Display { pub raw_handle: windows::Win32::Graphics::Gdi::HMONITOR, #[cfg(target_os = "macos")] - pub raw_handle: core_graphics_helmer_fork::display::CGDisplay, + pub raw_handle: cidre::cg::DirectDisplayId, } #[derive(Debug, Clone)]