Repository navigation
High-quality and lossless video over USB - #12
Merged
Merged
Conversation
The encoders ran CBR with a two-frame VBV, which capped the first IDR near twice the mean frame size (about 30 dB PSNR on a desktop at 46 Mbit/s); with an infinite GOP and damage-driven capture that blocky frame stayed on screen. Encoders now use quality-targeted VBR (NVENC cq 19, VAAPI VBR or CQP qp 20, libx264 crf 20) with a 2x peak and a four-frame VBV at the peak rate, giving about 50 dB on the first frame and far smaller frames on a still screen. Protocol 0.7 adds Control/18 StreamReport: the wanted bitrate, whether it came from settings, the link ceiling, every encoder and option set the host tried with its error, and the rate control that opened. The Android app shows it for a few seconds as an on-screen display in the bottom-left corner, with the codec and final rate in a larger line.
Protocol 0.8 adds Control/22 ClientPrefs, sent by the client after ClientHdr: a preferred codec (auto, H.264, HEVC, AV1) and a quality level. Normal keeps quality-targeted VBR; High uses a constant QP of 10; Lossless uses HEVC lossless (4:2:0) and falls back to High when the encoder or codec cannot do it. Levels above Normal apply only over USB. StreamReport moves to Control/21 and reports the requested and applied quality and codec; 0.7 and Control/18-20 stay reserved for audio. The Linux host now offers 8-bit SDR HEVC next to H.264 (HEVC was HDR10-only), with the bit depth explicit on each encoder plan. ezd-host run gains --codec and --quality, which override the client. The Android settings gain a Video section with the codec and the USB quality, sent with the capabilities on every connection, and the OSD shows the requested and applied quality and a lossless headline.
…1a081 # Conflicts: # android/app/src/main/kotlin/com/librestatic/ezdisplay/MainActivity.kt # android/app/src/main/kotlin/com/librestatic/ezdisplay/settings/SettingsScreen.kt # android/app/src/main/kotlin/com/librestatic/ezdisplay/settings/SettingsStore.kt # android/app/src/main/res/values-de/strings.xml # android/app/src/main/res/values-es/strings.xml # android/app/src/main/res/values-fr/strings.xml # android/app/src/main/res/values-it/strings.xml # android/app/src/main/res/values-pt/strings.xml # android/app/src/main/res/values/strings.xml # android/app/src/test/kotlin/com/librestatic/ezdisplay/settings/SettingsScreenshotTest.kt # android/app/src/test/kotlin/com/librestatic/ezdisplay/settings/SettingsStoreTest.kt # crates/ezd-android/src/caps.rs # crates/ezd-android/src/session.rs # crates/ezd-client-core/src/session.rs # crates/ezd-fake-client/i18n/de/ezd-fake-client.ftl # crates/ezd-fake-client/i18n/en/ezd-fake-client.ftl # crates/ezd-fake-client/i18n/es/ezd-fake-client.ftl # crates/ezd-fake-client/i18n/fr/ezd-fake-client.ftl # crates/ezd-fake-client/i18n/it/ezd-fake-client.ftl # crates/ezd-fake-client/i18n/pt/ezd-fake-client.ftl # crates/ezd-fake-client/src/lib.rs # crates/ezd-fake-client/src/main.rs # crates/ezd-host-core/src/lib.rs # crates/ezd-host-core/src/session.rs # crates/ezd-host-core/src/source.rs # crates/ezd-host-service/src/config.rs # crates/ezd-host-service/src/lib.rs # crates/ezd-host-service/src/service.rs # crates/ezd-host/src/run.rs # crates/ezd-proto/src/lib.rs # crates/ezd-proto/src/msg.rs # crates/ezd-proto/src/negotiate.rs # docs/protocol.md
The portal names a virtual output after the requesting app id, which has dots, and kscreen-doctor splits its arguments on dots. The custom 120 Hz mode was never added and the tablet ran at 60 Hz. Use the numeric id and check the refresh rate, not only the size, after switching.
The writer used 16 KiB chunks, a multiple of the endpoint's max packet, so transfer_len split every chunk into 16383 + 1 bytes. About 44% of the transfers carried one byte and each paid a full round trip to the tablet, whose accessory gadget takes at most 16 KiB per read. An odd write size is never split. Bulk reads stay at 16 KiB. With a full-screen scroll (about 135 KB per frame) the link now moves a frame in about 7.3 ms instead of 11-16 ms.
Lossless frames of moving content are around 1 MB at 2960x1848 and cap the stream at about 10 fps. At Lossless the host now encodes motion with the High set (QP 10) and, 150 ms after the last new frame, re-encodes that frame with a second, lossless encoder as one IDR with its own parameter sets. A full-screen scroll runs at about 40 fps with ~80 KB frames, and the still image becomes exact a moment after it stops.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets the tablet pick the video codec and quality level for USB streaming, and makes the host report which stream was actually negotiated. Also raises first-frame quality, fixes KDE mode switching on virtual outputs, speeds up AOA bulk writes, and makes still frames exact at the Lossless level.
Changes
Scope notes
docs/protocol.md) was updated for the new negotiation fields.Verification
cargo test -p ezd-host-linux: 186 passed, 1 ignored hardware test (run separately; passed on a GTX 1650 with NVENC).cargo clippy -p ezd-host-linux --all-targets: clean.Closes: no issue number was provided.