@desklink/host 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +44 -0
- package/README.md +266 -0
- package/bin/desklink-host.mjs +113 -0
- package/dist/bridge.d.ts +57 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +208 -0
- package/dist/bridge.js.map +1 -0
- package/dist/engineProcess.d.ts +82 -0
- package/dist/engineProcess.d.ts.map +1 -0
- package/dist/engineProcess.js +243 -0
- package/dist/engineProcess.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +169 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +18 -0
- package/dist/protocol.js.map +1 -0
- package/dist/resolveEngine.d.ts +34 -0
- package/dist/resolveEngine.d.ts.map +1 -0
- package/dist/resolveEngine.js +103 -0
- package/dist/resolveEngine.js.map +1 -0
- package/docs/BOUNDARY.md +145 -0
- package/docs/PROTOCOL.md +363 -0
- package/engine/Cargo.lock +3077 -0
- package/engine/Cargo.toml +37 -0
- package/engine/build.rs +107 -0
- package/engine/native/inputtino_shim.cpp +11 -0
- package/engine/native/vpx_shim.c +184 -0
- package/engine/native/wrapper.h +7 -0
- package/engine/src/capture.rs +510 -0
- package/engine/src/clipboard.rs +132 -0
- package/engine/src/convert.rs +299 -0
- package/engine/src/encoder.rs +204 -0
- package/engine/src/input.rs +355 -0
- package/engine/src/keymap.rs +338 -0
- package/engine/src/main.rs +614 -0
- package/engine/src/peer.rs +775 -0
- package/engine/src/portal.rs +115 -0
- package/engine/src/protocol.rs +331 -0
- package/engine/src/session.rs +2159 -0
- package/engine/src/x11.rs +244 -0
- package/engine/vendor/inputtino/.clang-format +166 -0
- package/engine/vendor/inputtino/.clang-tidy +30 -0
- package/engine/vendor/inputtino/.dockerignore +11 -0
- package/engine/vendor/inputtino/.github/workflows/mirror-repo.yml +14 -0
- package/engine/vendor/inputtino/.github/workflows/python-lint-format-test-typecheck.yml +124 -0
- package/engine/vendor/inputtino/.github/workflows/python-test-install.yaml +49 -0
- package/engine/vendor/inputtino/.github/workflows/rust.yml +40 -0
- package/engine/vendor/inputtino/CMakeLists.txt +187 -0
- package/engine/vendor/inputtino/LICENSE +21 -0
- package/engine/vendor/inputtino/README.md +110 -0
- package/engine/vendor/inputtino/bindings/python/.devcontainer/Dockerfile +23 -0
- package/engine/vendor/inputtino/bindings/python/.devcontainer/devcontainer.json +28 -0
- package/engine/vendor/inputtino/bindings/python/.python-version +1 -0
- package/engine/vendor/inputtino/bindings/python/CMakeLists.txt +23 -0
- package/engine/vendor/inputtino/bindings/python/CPPLINT.cfg +2 -0
- package/engine/vendor/inputtino/bindings/python/Makefile +49 -0
- package/engine/vendor/inputtino/bindings/python/README.md +215 -0
- package/engine/vendor/inputtino/bindings/python/pyproject.toml +178 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/__init__.py +43 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/_core.pyi +533 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/base.py +63 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/joypad.py +248 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/keyboard.py +256 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/mouse.py +106 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/pentablet.py +73 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/py.typed +0 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/touchscreen.py +61 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/trackpad.py +74 -0
- package/engine/vendor/inputtino/bindings/python/src/main.cpp +217 -0
- package/engine/vendor/inputtino/bindings/python/tests/__init__.py +0 -0
- package/engine/vendor/inputtino/bindings/python/tests/helpers.py +3 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_base.py +60 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_inputtino.py +5 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_joypad.py +332 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_keyboard.py +164 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_mouse.py +185 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_pentablet.py +198 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_touchscreen.py +144 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_trackpad.py +146 -0
- package/engine/vendor/inputtino/bindings/python/uv.lock +390 -0
- package/engine/vendor/inputtino/bindings/rust/Cargo.toml +6 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/.dockerignore +1 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/Cargo.toml +18 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/examples/keyboard.rs +33 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/examples/mouse.rs +17 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/common.rs +116 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/error.rs +17 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad.rs +74 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_nintendo.rs +135 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_ps5.rs +280 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_xbox.rs +134 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/keyboard.rs +76 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/lib.rs +32 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/mouse.rs +178 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/common.rs +38 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/joypads.rs +150 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/keyboard.rs +73 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/mouse.rs +139 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/.dockerignore +1 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/Cargo.toml +12 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/build.rs +48 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/src/lib.rs +5 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/wrapper.h +1 -0
- package/engine/vendor/inputtino/cmake/utils.cmake +9 -0
- package/engine/vendor/inputtino/docker/Dockerfile +70 -0
- package/engine/vendor/inputtino/include/inputtino/input.h +324 -0
- package/engine/vendor/inputtino/include/inputtino/input.hpp +466 -0
- package/engine/vendor/inputtino/include/inputtino/result.hpp +37 -0
- package/engine/vendor/inputtino/share/pkgconfig/libinputtino.pc.in +17 -0
- package/engine/vendor/inputtino/src/c-bindings/helpers.hpp +19 -0
- package/engine/vendor/inputtino/src/c-bindings/joypad_ps5.cpp +115 -0
- package/engine/vendor/inputtino/src/c-bindings/joypad_switch.cpp +63 -0
- package/engine/vendor/inputtino/src/c-bindings/joypad_xone.cpp +62 -0
- package/engine/vendor/inputtino/src/c-bindings/keyboard.cpp +42 -0
- package/engine/vendor/inputtino/src/c-bindings/mouse.cpp +67 -0
- package/engine/vendor/inputtino/src/c-bindings/pen_tablet.cpp +50 -0
- package/engine/vendor/inputtino/src/c-bindings/touchscreen.cpp +43 -0
- package/engine/vendor/inputtino/src/c-bindings/trackpad.cpp +49 -0
- package/engine/vendor/inputtino/src/uhid/README.adoc +63 -0
- package/engine/vendor/inputtino/src/uhid/include/crc32.hpp +38 -0
- package/engine/vendor/inputtino/src/uhid/include/uhid/protected_types.hpp +36 -0
- package/engine/vendor/inputtino/src/uhid/include/uhid/ps5.hpp +550 -0
- package/engine/vendor/inputtino/src/uhid/include/uhid/uhid.hpp +168 -0
- package/engine/vendor/inputtino/src/uhid/joypad_ps5.cpp +580 -0
- package/engine/vendor/inputtino/src/uinput/include/inputtino/keyboard.hpp +84 -0
- package/engine/vendor/inputtino/src/uinput/include/inputtino/protected_ps5_types.hpp +7 -0
- package/engine/vendor/inputtino/src/uinput/include/inputtino/protected_types.hpp +110 -0
- package/engine/vendor/inputtino/src/uinput/joypad_nintendo.cpp +190 -0
- package/engine/vendor/inputtino/src/uinput/joypad_ps.cpp +203 -0
- package/engine/vendor/inputtino/src/uinput/joypad_utils.hpp +246 -0
- package/engine/vendor/inputtino/src/uinput/joypad_xbox.cpp +190 -0
- package/engine/vendor/inputtino/src/uinput/keyboard.cpp +120 -0
- package/engine/vendor/inputtino/src/uinput/mouse.cpp +199 -0
- package/engine/vendor/inputtino/src/uinput/pentablet.cpp +162 -0
- package/engine/vendor/inputtino/src/uinput/touchscreen.cpp +140 -0
- package/engine/vendor/inputtino/src/uinput/trackpad.cpp +192 -0
- package/examples/reference-client.html +428 -0
- package/package.json +38 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "desklink-host"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
license = "Apache-2.0"
|
|
6
|
+
description = "Per-user on-demand desktop capture, encode and input engine speaking a versioned local control protocol"
|
|
7
|
+
publish = false
|
|
8
|
+
|
|
9
|
+
[[bin]]
|
|
10
|
+
name = "desklink-host"
|
|
11
|
+
path = "src/main.rs"
|
|
12
|
+
|
|
13
|
+
[dependencies]
|
|
14
|
+
anyhow = "1"
|
|
15
|
+
serde = { version = "1", features = ["derive"] }
|
|
16
|
+
serde_json = "1"
|
|
17
|
+
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "sync", "time", "signal"] }
|
|
18
|
+
futures-util = "0.3"
|
|
19
|
+
ashpd = { version = "0.11", default-features = false, features = ["tokio"] }
|
|
20
|
+
pipewire = { version = "0.10", features = ["v0_3_44"] }
|
|
21
|
+
libc = "0.2"
|
|
22
|
+
bytes = "1"
|
|
23
|
+
webrtc = { version = "0.21", default-features = false, features = ["runtime-tokio", "crypto-ring"] }
|
|
24
|
+
rtc = { version = "0.21", default-features = false, features = ["crypto-ring"] }
|
|
25
|
+
xkbcommon = "0.8"
|
|
26
|
+
x11rb = { version = "0.14", default-features = false, features = ["allow-unsafe-code", "xtest"] }
|
|
27
|
+
wl-clipboard-rs = "0.9"
|
|
28
|
+
log = "0.4"
|
|
29
|
+
async-trait = "0.1"
|
|
30
|
+
rand = "0.8"
|
|
31
|
+
|
|
32
|
+
[build-dependencies]
|
|
33
|
+
cc = "1"
|
|
34
|
+
|
|
35
|
+
[profile.release]
|
|
36
|
+
lto = "thin"
|
|
37
|
+
opt-level = 2
|
package/engine/build.rs
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//! Native dependencies of the engine.
|
|
2
|
+
//!
|
|
3
|
+
//! Two permissive C libraries, both built or linked from this machine's own
|
|
4
|
+
//! sources — no prebuilt binary is fetched, and nothing is installed:
|
|
5
|
+
//!
|
|
6
|
+
//! * libvpx (BSD-3-Clause) — VP9 encode, through `native/vpx_shim.c` so the
|
|
7
|
+
//! versioned encoder config struct is laid out by a C compiler.
|
|
8
|
+
//! * inputtino (MIT, vendored under `vendor/`) — virtual mouse and keyboard
|
|
9
|
+
//! over `uinput`/`libevdev`, built by its own CMake project into a static
|
|
10
|
+
//! library and called through its documented C API.
|
|
11
|
+
//!
|
|
12
|
+
//! Both are required to build the engine; the README lists the system packages
|
|
13
|
+
//! they need. Whether input can actually be injected is a separate, runtime
|
|
14
|
+
//! question the engine answers through its own `/dev/uinput` probe.
|
|
15
|
+
//!
|
|
16
|
+
//! `DESKLINK_VPX_STATIC_DIR` names a libvpx install prefix (`include/`, `lib/`)
|
|
17
|
+
//! to link statically instead. The prebuilt engine uses it, because libvpx's
|
|
18
|
+
//! soname changes with every major release and a distributed executable must not
|
|
19
|
+
//! depend on whichever one a given distribution ships.
|
|
20
|
+
|
|
21
|
+
use std::path::{Path, PathBuf};
|
|
22
|
+
|
|
23
|
+
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
24
|
+
println!("cargo:rerun-if-changed=native/vpx_shim.c");
|
|
25
|
+
println!("cargo:rerun-if-changed=native/inputtino_shim.cpp");
|
|
26
|
+
println!("cargo:rerun-if-changed=vendor/inputtino/src/uinput/include/inputtino/keyboard.hpp");
|
|
27
|
+
println!("cargo:rerun-if-changed=vendor/inputtino/include/inputtino/input.h");
|
|
28
|
+
println!("cargo:rerun-if-changed=vendor/inputtino/CMakeLists.txt");
|
|
29
|
+
|
|
30
|
+
println!("cargo:rerun-if-env-changed=DESKLINK_VPX_STATIC_DIR");
|
|
31
|
+
|
|
32
|
+
let static_vpx = std::env::var_os("DESKLINK_VPX_STATIC_DIR").map(PathBuf::from);
|
|
33
|
+
let mut shim = cc::Build::new();
|
|
34
|
+
shim.file("native/vpx_shim.c")
|
|
35
|
+
.flag_if_supported("-Wno-unused-parameter");
|
|
36
|
+
if let Some(prefix) = &static_vpx {
|
|
37
|
+
shim.include(prefix.join("include"));
|
|
38
|
+
}
|
|
39
|
+
shim.compile("dlvpx");
|
|
40
|
+
match &static_vpx {
|
|
41
|
+
Some(prefix) => {
|
|
42
|
+
println!(
|
|
43
|
+
"cargo:rustc-link-search=native={}",
|
|
44
|
+
prefix.join("lib").display()
|
|
45
|
+
);
|
|
46
|
+
println!("cargo:rustc-link-lib=static=vpx");
|
|
47
|
+
}
|
|
48
|
+
None => println!("cargo:rustc-link-lib=vpx"),
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
cc::Build::new()
|
|
52
|
+
.cpp(true)
|
|
53
|
+
.std("c++17")
|
|
54
|
+
.include("vendor/inputtino/src/uinput/include")
|
|
55
|
+
.file("native/inputtino_shim.cpp")
|
|
56
|
+
.compile("dlinputkey");
|
|
57
|
+
build_inputtino(&PathBuf::from(std::env::var("OUT_DIR")?))?;
|
|
58
|
+
Ok(())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fn build_inputtino(out: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
|
62
|
+
let source = Path::new("vendor/inputtino");
|
|
63
|
+
if !source.join("CMakeLists.txt").exists() {
|
|
64
|
+
return Err("the vendored inputtino source is missing from engine/vendor/inputtino".into());
|
|
65
|
+
}
|
|
66
|
+
let destination = out.join("inputtino-build");
|
|
67
|
+
let configured = std::process::Command::new("cmake")
|
|
68
|
+
.args([
|
|
69
|
+
"-S",
|
|
70
|
+
&source.display().to_string(),
|
|
71
|
+
"-B",
|
|
72
|
+
&destination.display().to_string(),
|
|
73
|
+
"-DCMAKE_BUILD_TYPE=Release",
|
|
74
|
+
"-DBUILD_SHARED_LIBS=OFF",
|
|
75
|
+
"-DBUILD_C_BINDINGS=ON",
|
|
76
|
+
"-DBUILD_TESTING=OFF",
|
|
77
|
+
"-DUSE_UHID=OFF",
|
|
78
|
+
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
|
|
79
|
+
])
|
|
80
|
+
.status()
|
|
81
|
+
.is_ok_and(|s| s.success());
|
|
82
|
+
if !configured {
|
|
83
|
+
return Err(
|
|
84
|
+
"cmake could not configure the vendored inputtino project; install cmake and libevdev"
|
|
85
|
+
.into(),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
let compiled = std::process::Command::new("cmake")
|
|
89
|
+
.args([
|
|
90
|
+
"--build",
|
|
91
|
+
&destination.display().to_string(),
|
|
92
|
+
"--target",
|
|
93
|
+
"libinputtino",
|
|
94
|
+
])
|
|
95
|
+
.status()
|
|
96
|
+
.is_ok_and(|s| s.success());
|
|
97
|
+
if !compiled {
|
|
98
|
+
return Err("cmake could not build the vendored inputtino project".into());
|
|
99
|
+
}
|
|
100
|
+
println!("cargo:rustc-link-search=native={}", destination.display());
|
|
101
|
+
println!("cargo:rustc-link-lib=static=libinputtino");
|
|
102
|
+
println!("cargo:rustc-link-lib=dylib=stdc++");
|
|
103
|
+
// inputtino statically embeds its own code but not libevdev, which it calls
|
|
104
|
+
// into for uinput device management.
|
|
105
|
+
println!("cargo:rustc-link-lib=dylib=evdev");
|
|
106
|
+
Ok(())
|
|
107
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#include <inputtino/keyboard.hpp>
|
|
2
|
+
|
|
3
|
+
// XKB plans physical evdev keys; inputtino's public API takes Moonlight/Windows
|
|
4
|
+
// virtual-key identities. Use its complete mapping rather than duplicating a
|
|
5
|
+
// US character table (which would break other layouts and named keys).
|
|
6
|
+
extern "C" short dl_inputtino_keycode(short evdev_code) {
|
|
7
|
+
for (const auto &[virtual_key, mapping] : inputtino::keyboard::key_mappings) {
|
|
8
|
+
if (mapping.linux_code == evdev_code) return virtual_key;
|
|
9
|
+
}
|
|
10
|
+
return -1;
|
|
11
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thin C surface over libvpx's VP9 encoder.
|
|
3
|
+
*
|
|
4
|
+
* libvpx configures its encoder through a large versioned struct whose layout
|
|
5
|
+
* follows the *header the library was built against*, not the one on this
|
|
6
|
+
* machine. Doing that configuration in C, where the compiler and the headers
|
|
7
|
+
* agree, keeps a wrong offset from silently producing a broken stream; the
|
|
8
|
+
* Rust side only ever sees an opaque handle and a byte slice.
|
|
9
|
+
*
|
|
10
|
+
* libvpx is BSD-3-Clause. No code here is derived from any encoder
|
|
11
|
+
* implementation: it is the documented configuration path for the public API.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include <stddef.h>
|
|
15
|
+
#include <stdint.h>
|
|
16
|
+
#include <stdlib.h>
|
|
17
|
+
#include <string.h>
|
|
18
|
+
|
|
19
|
+
#include <vpx/vp8cx.h>
|
|
20
|
+
#include <vpx/vpx_codec.h>
|
|
21
|
+
#include <vpx/vpx_encoder.h>
|
|
22
|
+
#include <vpx/vpx_image.h>
|
|
23
|
+
|
|
24
|
+
/* The quantizer ceiling while the desktop moves. Refinement frames lower it. */
|
|
25
|
+
#define DL_VPX_MOTION_MAX_Q 52
|
|
26
|
+
|
|
27
|
+
typedef struct {
|
|
28
|
+
vpx_codec_ctx_t ctx;
|
|
29
|
+
vpx_codec_enc_cfg_t cfg;
|
|
30
|
+
int width;
|
|
31
|
+
int height;
|
|
32
|
+
int frame_index;
|
|
33
|
+
/* The packet libvpx last produced; valid until the next encode call. */
|
|
34
|
+
const void *packet;
|
|
35
|
+
size_t packet_size;
|
|
36
|
+
int packet_is_key;
|
|
37
|
+
} dl_vpx_encoder;
|
|
38
|
+
|
|
39
|
+
/* Returns NULL when libvpx refuses the configuration, which is reported rather
|
|
40
|
+
* than papered over: a silently unconfigured encoder looks like a network bug. */
|
|
41
|
+
dl_vpx_encoder *dl_vpx_create(int width, int height, int bitrate_kbps, int fps,
|
|
42
|
+
int threads, int cpu_used) {
|
|
43
|
+
if (width <= 0 || height <= 0 || bitrate_kbps <= 0 || fps <= 0) {
|
|
44
|
+
return NULL;
|
|
45
|
+
}
|
|
46
|
+
dl_vpx_encoder *self = calloc(1, sizeof(dl_vpx_encoder));
|
|
47
|
+
if (self == NULL) {
|
|
48
|
+
return NULL;
|
|
49
|
+
}
|
|
50
|
+
vpx_codec_iface_t *iface = vpx_codec_vp9_cx();
|
|
51
|
+
if (vpx_codec_enc_config_default(iface, &self->cfg, 0) != VPX_CODEC_OK) {
|
|
52
|
+
free(self);
|
|
53
|
+
return NULL;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
self->cfg.g_w = (unsigned int)width;
|
|
57
|
+
self->cfg.g_h = (unsigned int)height;
|
|
58
|
+
self->cfg.g_timebase.num = 1;
|
|
59
|
+
self->cfg.g_timebase.den = fps;
|
|
60
|
+
self->cfg.g_profile = 0;
|
|
61
|
+
self->cfg.g_bit_depth = VPX_BITS_8;
|
|
62
|
+
self->cfg.g_input_bit_depth = 8;
|
|
63
|
+
self->cfg.g_pass = VPX_RC_ONE_PASS;
|
|
64
|
+
self->cfg.g_lag_in_frames = 0;
|
|
65
|
+
self->cfg.g_threads = (unsigned int)(threads < 1 ? 1 : threads);
|
|
66
|
+
self->cfg.rc_end_usage = VPX_CBR;
|
|
67
|
+
self->cfg.rc_target_bitrate = (unsigned int)bitrate_kbps;
|
|
68
|
+
self->cfg.rc_min_quantizer = 2;
|
|
69
|
+
self->cfg.rc_max_quantizer = DL_VPX_MOTION_MAX_Q;
|
|
70
|
+
self->cfg.rc_buf_sz = 1000;
|
|
71
|
+
self->cfg.rc_buf_initial_sz = 500;
|
|
72
|
+
self->cfg.rc_buf_optimal_sz = 600;
|
|
73
|
+
self->cfg.rc_undershoot_pct = 50;
|
|
74
|
+
self->cfg.rc_overshoot_pct = 50;
|
|
75
|
+
self->cfg.rc_dropframe_thresh = 0;
|
|
76
|
+
/* Key frames only when asked: the first frame, a receiver that lost its
|
|
77
|
+
* reference (PLI/FIR) or a transport that just connected. On a desktop a
|
|
78
|
+
* periodic key frame is the most expensive frame in the stream and the one
|
|
79
|
+
* that resets a sharp picture to a soft one. */
|
|
80
|
+
self->cfg.kf_mode = VPX_KF_DISABLED;
|
|
81
|
+
|
|
82
|
+
if (vpx_codec_enc_init(&self->ctx, iface, &self->cfg, 0) != VPX_CODEC_OK) {
|
|
83
|
+
free(self);
|
|
84
|
+
return NULL;
|
|
85
|
+
}
|
|
86
|
+
vpx_codec_control(&self->ctx, VP8E_SET_CPUUSED, cpu_used);
|
|
87
|
+
/* A key frame may take several frames' budget: it is rare, and a starved
|
|
88
|
+
* one is a soft picture until the refinement pass lands. */
|
|
89
|
+
vpx_codec_control(&self->ctx, VP8E_SET_MAX_INTRA_BITRATE_PCT, 900);
|
|
90
|
+
vpx_codec_control(&self->ctx, VP9E_SET_ROW_MT, 1);
|
|
91
|
+
/* Screen content: text and flat colour, not camera noise. This is what
|
|
92
|
+
* keeps glyph edges instead of smearing them into blocks. */
|
|
93
|
+
vpx_codec_control(&self->ctx, VP9E_SET_TUNE_CONTENT, VP9E_CONTENT_SCREEN);
|
|
94
|
+
/* Cyclic refresh re-codes static areas at a finer quantizer over the next
|
|
95
|
+
* frames, so an unchanged desktop keeps converging on sharp. */
|
|
96
|
+
vpx_codec_control(&self->ctx, VP9E_SET_AQ_MODE, 3);
|
|
97
|
+
vpx_codec_control(&self->ctx, VP9E_SET_NOISE_SENSITIVITY, 0);
|
|
98
|
+
/* Columns let the encoder and the phone's decoder split a 4K frame; libvpx
|
|
99
|
+
* caps this at what the width allows. */
|
|
100
|
+
vpx_codec_control(&self->ctx, VP9E_SET_TILE_COLUMNS, 3);
|
|
101
|
+
vpx_codec_control(&self->ctx, VP9E_SET_COLOR_SPACE, VPX_CS_BT_601);
|
|
102
|
+
|
|
103
|
+
self->width = width;
|
|
104
|
+
self->height = height;
|
|
105
|
+
return self;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Encode one tightly packed I420 frame. Returns:
|
|
109
|
+
* 1 a packet is available through dl_vpx_packet_*
|
|
110
|
+
* 0 libvpx held the frame (should not happen with zero lookahead)
|
|
111
|
+
* -1 libvpx rejected the frame
|
|
112
|
+
*/
|
|
113
|
+
int dl_vpx_encode(dl_vpx_encoder *self, const uint8_t *i420, int force_keyframe) {
|
|
114
|
+
if (self == NULL || i420 == NULL) {
|
|
115
|
+
return -1;
|
|
116
|
+
}
|
|
117
|
+
vpx_image_t image;
|
|
118
|
+
if (vpx_img_wrap(&image, VPX_IMG_FMT_I420, (unsigned int)self->width,
|
|
119
|
+
(unsigned int)self->height, 1, (unsigned char *)i420) == NULL) {
|
|
120
|
+
return -1;
|
|
121
|
+
}
|
|
122
|
+
if (vpx_codec_encode(&self->ctx, &image, self->frame_index, 1,
|
|
123
|
+
force_keyframe ? VPX_EFLAG_FORCE_KF : 0,
|
|
124
|
+
VPX_DL_REALTIME) != VPX_CODEC_OK) {
|
|
125
|
+
return -1;
|
|
126
|
+
}
|
|
127
|
+
self->frame_index++;
|
|
128
|
+
|
|
129
|
+
self->packet = NULL;
|
|
130
|
+
self->packet_size = 0;
|
|
131
|
+
vpx_codec_iter_t iter = NULL;
|
|
132
|
+
const vpx_codec_cx_pkt_t *pkt;
|
|
133
|
+
while ((pkt = vpx_codec_get_cx_data(&self->ctx, &iter)) != NULL) {
|
|
134
|
+
if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
self->packet = pkt->data.frame.buf;
|
|
138
|
+
self->packet_size = pkt->data.frame.sz;
|
|
139
|
+
self->packet_is_key = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
return self->packet == NULL ? 0 : 1;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Change the rate target and the quantizer ceiling for the frames that follow.
|
|
146
|
+
* A low ceiling on an unchanged frame is a refinement pass: the encoder spends
|
|
147
|
+
* what it takes to make the picture sharp, once, instead of every frame.
|
|
148
|
+
* Returns 0 on success. */
|
|
149
|
+
int dl_vpx_reconfigure(dl_vpx_encoder *self, int bitrate_kbps, int max_quantizer) {
|
|
150
|
+
if (self == NULL || bitrate_kbps <= 0) {
|
|
151
|
+
return -1;
|
|
152
|
+
}
|
|
153
|
+
if (max_quantizer < (int)self->cfg.rc_min_quantizer) {
|
|
154
|
+
max_quantizer = (int)self->cfg.rc_min_quantizer;
|
|
155
|
+
}
|
|
156
|
+
if (max_quantizer > 63) {
|
|
157
|
+
max_quantizer = 63;
|
|
158
|
+
}
|
|
159
|
+
if (self->cfg.rc_target_bitrate == (unsigned int)bitrate_kbps &&
|
|
160
|
+
self->cfg.rc_max_quantizer == (unsigned int)max_quantizer) {
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
self->cfg.rc_target_bitrate = (unsigned int)bitrate_kbps;
|
|
164
|
+
self->cfg.rc_max_quantizer = (unsigned int)max_quantizer;
|
|
165
|
+
return vpx_codec_enc_config_set(&self->ctx, &self->cfg) == VPX_CODEC_OK ? 0 : -1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
int dl_vpx_motion_max_q(void) { return DL_VPX_MOTION_MAX_Q; }
|
|
169
|
+
|
|
170
|
+
const uint8_t *dl_vpx_packet_data(const dl_vpx_encoder *self) {
|
|
171
|
+
return (const uint8_t *)self->packet;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
size_t dl_vpx_packet_size(const dl_vpx_encoder *self) { return self->packet_size; }
|
|
175
|
+
|
|
176
|
+
int dl_vpx_packet_is_key(const dl_vpx_encoder *self) { return self->packet_is_key; }
|
|
177
|
+
|
|
178
|
+
void dl_vpx_destroy(dl_vpx_encoder *self) {
|
|
179
|
+
if (self == NULL) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
vpx_codec_destroy(&self->ctx);
|
|
183
|
+
free(self);
|
|
184
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/* The two permissive native APIs the engine links. Kept in one translation
|
|
2
|
+
* unit so bindgen sees the same libc types for both. */
|
|
3
|
+
#include <vpx/vpx_codec.h>
|
|
4
|
+
#include <vpx/vpx_encoder.h>
|
|
5
|
+
#include <vpx/vpx_image.h>
|
|
6
|
+
#include <vpx/vp8cx.h>
|
|
7
|
+
#include <inputtino/input.h>
|