From 001f152eeca7e53a3d1069f01bab6e6114bd118c Mon Sep 17 00:00:00 2001 From: infrost Date: Wed, 8 Jul 2026 02:37:13 +0100 Subject: [PATCH] =?UTF-8?q?Parallel=20QR=20=E9=BB=98=E8=AE=A4=E6=94=B9?= =?UTF-8?q?=E6=88=90=204=EF=BC=8C=E9=80=89=E9=A1=B9=E6=89=A9=E5=88=B0=201/?= =?UTF-8?q?2/4/6/8=EF=BC=8Clive=20=E5=92=8C=20GIF=20=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E9=83=BD=E6=94=AF=E6=8C=81=206=20=3D=203x2=E3=80=818=20=3D=204?= =?UTF-8?q?x2=E3=80=82=20Sender=20=E9=87=8C=20QR=20encoder=E3=80=81FEC=20c?= =?UTF-8?q?odec=E3=80=81RaptorQ=20repair=20=E9=83=BD=E6=94=B6=E8=BF=9B?= =?UTF-8?q?=E4=BA=86=20Advanced=20settings=E3=80=82=20RaptorQ=20repair=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=BB=8E=2020%=20=E6=94=B9=E6=88=90=2010%?= =?UTF-8?q?=E3=80=82=20Receiver=20=E7=9A=84=20Max=20symbols=20=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E6=98=BE=E7=A4=BA=E4=B8=BA=20Auto=20(4)=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E4=B8=94=E6=89=8B=E5=8A=A8=E6=94=AF=E6=8C=81=206/8?= =?UTF-8?q?=E3=80=82=20Sender=20=E9=80=89=206/8=20=E6=97=B6=E4=BC=9A?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=EF=BC=9AReceiver=20=E7=9A=84=20Auto=20(4)=20?= =?UTF-8?q?=E5=8F=AA=E6=89=AB=204=20=E4=B8=AA=EF=BC=8C=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E6=89=8B=E5=8A=A8=E6=8A=8A=20Max=20symbols=20=E8=AE=BE?= =?UTF-8?q?=E6=88=90=E5=AF=B9=E5=BA=94=E7=9A=84=206/8=E3=80=82=20=E4=BF=AE?= =?UTF-8?q?=E4=BA=86=20fast=5Fqr=20=E5=AE=B9=E9=87=8F=EF=BC=9A=E5=8F=AA?= =?UTF-8?q?=E6=9C=89=20ZXing=20WASM=20=E7=BB=A7=E7=BB=AD=E6=89=A3=E9=82=A3?= =?UTF-8?q?=202=20bytes=EF=BC=8Cfast=5Fqr=20WASM=20=E5=92=8C=20JS=20QR=20?= =?UTF-8?q?=E9=83=BD=E4=BD=BF=E7=94=A8=E5=AE=8C=E6=95=B4=20QR=20byte=20cap?= =?UTF-8?q?acity=E3=80=82=20=E9=A1=BA=E6=89=8B=E4=BF=AE=E4=BA=86=20normali?= =?UTF-8?q?zeFecCodec('js-rlnc')=20=E4=BC=9A=E8=A2=AB=E5=BD=92=E5=9B=9E=20?= =?UTF-8?q?wasm=20=E9=BB=98=E8=AE=A4=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E7=84=B6=E9=AB=98=E7=BA=A7=E8=AE=BE=E7=BD=AE=E9=87=8C?= =?UTF-8?q?=E7=9A=84=20JS=20compatible=20=E4=BC=9A=E9=80=89=E4=B8=8D?= =?UTF-8?q?=E4=BD=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/routes/receiver.tsx | 6 +- src/app/routes/sender.tsx | 138 ++++++++++++++++----------- src/core/fec/codec.ts | 7 +- src/core/protocol/profiles.ts | 10 +- src/core/qr/decode_settings.ts | 4 +- src/core/qr/qr_decode.ts | 3 +- src/core/sender/parallel_striping.ts | 2 +- src/tests/test_qr_modules.test.ts | 52 +++++++++- src/workers/gif.worker.ts | 6 +- 9 files changed, 150 insertions(+), 78 deletions(-) diff --git a/src/app/routes/receiver.tsx b/src/app/routes/receiver.tsx index 47f50d7..a322ab2 100644 --- a/src/app/routes/receiver.tsx +++ b/src/app/routes/receiver.tsx @@ -1133,11 +1133,13 @@ function formatDecodePreset(value: DecodePresetId): string { function parseMaxSymbolsMode(value: string): MaxSymbolsMode { if (value === 'auto') return 'auto'; const parsed = Number(value); - return parsed === 1 || parsed === 2 || parsed === 4 ? parsed : DEFAULT_DECODE_SETTINGS.maxSymbols; + return parsed === 1 || parsed === 2 || parsed === 4 || parsed === 6 || parsed === 8 + ? parsed + : DEFAULT_DECODE_SETTINGS.maxSymbols; } function formatMaxSymbols(value: MaxSymbolsMode): string { - return value === 'auto' ? 'Auto' : String(value); + return value === 'auto' ? 'Auto (4)' : String(value); } function normalizeBinarizer(value: string): QrBinarizer { diff --git a/src/app/routes/sender.tsx b/src/app/routes/sender.tsx index f9c41d3..9e2bf7d 100644 --- a/src/app/routes/sender.tsx +++ b/src/app/routes/sender.tsx @@ -85,8 +85,8 @@ type CSSProps = Record; const MIN_FRAME_RATE_FPS = 2; const MAX_FRAME_RATE_FPS = 60; const DEFAULT_FRAME_RATE_FPS = 30; -const DEFAULT_PARALLEL_QR_COUNT: ParallelQRCount = 1; -const PARALLEL_QR_COUNTS: ParallelQRCount[] = [1, 2, 4]; +const DEFAULT_PARALLEL_QR_COUNT: ParallelQRCount = 4; +const PARALLEL_QR_COUNTS: ParallelQRCount[] = [1, 2, 4, 6, 8]; const FEC_CODEC_OPTIONS: FecCodec[] = ['wasm-raptorq', 'js-rlnc']; const LIVE_TARGET_PX = 360; const QR_QUIET_ZONE_MODULES = 4; @@ -258,6 +258,7 @@ export function SenderPage() { const [qrEncoder, setQrEncoder] = useState(DEFAULT_QR_ENCODER); const [fecCodec, setFecCodec] = useState(DEFAULT_FEC_CODEC); const [raptorqRepairPercent, setRaptorqRepairPercent] = useState(DEFAULT_RAPTORQ_REPAIR_PERCENT); + const [advancedGenerateOpen, setAdvancedGenerateOpen] = useState(false); const [frameRateFps, setFrameRateFps] = useState(DEFAULT_FRAME_RATE_FPS); const [actualLiveFps, setActualLiveFps] = useState(0); const [renderReadyPackets, setRenderReadyPackets] = useState(0); @@ -1023,63 +1024,76 @@ export function SenderPage() {
-
- QR encoder - {formatQREncoder(qrEncoder)} -
- -
-
-
- FEC codec - {formatFecCodec(fecCodec)} -
- -
- {fecCodec === 'wasm-raptorq' && ( -
-
- RaptorQ repair - {raptorqRepairPercent}% + {advancedGenerateOpen ? 'Hide advanced settings' : 'Advanced settings'} + + {advancedGenerateOpen && ( +
+ + + {fecCodec === 'wasm-raptorq' && ( + + )}
- handleRaptorQRepairPercentChange((e.target as HTMLInputElement).value)} - /> -
- Less QR - More repair -
-
- )} + )} +
QR speed @@ -1116,6 +1130,12 @@ export function SenderPage() { ))} + {parallelQRCount > 4 && ( +
+ Receiver Auto (4) scans up to 4 QR codes per frame. For {parallelQRCount} parallel QR, + set Receiver advanced settings - Max symbols to {parallelQRCount}. +
+ )}