qrstream 0.4.1__tar.gz

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.
@@ -0,0 +1,37 @@
1
+ name: publish-pypi
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ environment:
16
+ name: pypi
17
+ url: https://pypi.org/project/qrstream/
18
+
19
+ steps:
20
+ - name: Check out code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Set up Python
24
+ uses: actions/setup-python@v5
25
+ with:
26
+ python-version: '3.13'
27
+
28
+ - name: Set up uv
29
+ uses: astral-sh/setup-uv@v6
30
+ with:
31
+ enable-cache: true
32
+
33
+ - name: Build distributions
34
+ run: uv build
35
+
36
+ - name: Publish to PyPI
37
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,55 @@
1
+ name: test
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - 'dev/**'
8
+ pull_request:
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ test:
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ python-version:
21
+ - '3.10'
22
+ - '3.11'
23
+ - '3.12'
24
+ - '3.13'
25
+
26
+ steps:
27
+ - name: Check out code
28
+ uses: actions/checkout@v4
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: ${{ matrix.python-version }}
34
+
35
+ - name: Set up uv
36
+ uses: astral-sh/setup-uv@v6
37
+ with:
38
+ enable-cache: true
39
+
40
+ - name: Install dependencies
41
+ run: uv sync --dev
42
+
43
+ - name: Run tests
44
+ run: uv run pytest tests/ -v
45
+
46
+ - name: Build distributions
47
+ if: matrix.python-version == '3.13'
48
+ run: uv build
49
+
50
+ - name: Upload built distributions
51
+ if: matrix.python-version == '3.13'
52
+ uses: actions/upload-artifact@v4
53
+ with:
54
+ name: python-package-distributions
55
+ path: dist/
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+
9
+ # IDE
10
+ .idea/
11
+ .vscode/
12
+ .claude/
13
+ *.swp
14
+ *.swo
15
+
16
+ # CodeBuddy
17
+ .codebuddy/
18
+
19
+ # OS
20
+ .DS_Store
21
+ Thumbs.db
22
+
23
+ # Project data (keep locally, exclude from repo)
24
+ inputs/
25
+ outputs/
26
+ output
27
+ skills/
28
+
29
+ # Test / cache
30
+ .pytest_cache/
31
+ *.egg
qrstream-0.4.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David He
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,292 @@
1
+ Metadata-Version: 2.4
2
+ Name: qrstream
3
+ Version: 0.4.1
4
+ Summary: Encode and decode files via QR code video streams using LT fountain codes
5
+ Project-URL: Homepage, https://github.com/ddddavid-he/qrstream-enhanced
6
+ Project-URL: Repository, https://github.com/ddddavid-he/qrstream-enhanced.git
7
+ Project-URL: Issues, https://github.com/ddddavid-he/qrstream-enhanced/issues
8
+ Author-email: David He <hewei201031l@outlook.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 David He
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: erasure-code,fountain-code,lt-code,luby-transform,opencv,qr-code,video-transfer
32
+ Classifier: Development Status :: 5 - Production/Stable
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Operating System :: OS Independent
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Topic :: Multimedia :: Video
42
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
43
+ Requires-Python: >=3.10
44
+ Requires-Dist: numpy>=1.20.0
45
+ Requires-Dist: opencv-contrib-python>=4.5.0
46
+ Requires-Dist: qrcode[pil]>=7.0
47
+ Requires-Dist: tqdm>=4.60.0
48
+ Provides-Extra: dev
49
+ Requires-Dist: pytest>=9.0.2; extra == 'dev'
50
+ Description-Content-Type: text/markdown
51
+
52
+ # QRStream
53
+
54
+ [中文文档](README-zh.md)
55
+
56
+ Transfer arbitrary files through QR code video streams. Built on **LT Fountain Codes (Luby Transform)** for reliable, feedback-free data transmission — the original file can be fully recovered even if some frames are lost.
57
+
58
+ ## How It Works
59
+
60
+ ```
61
+ Encoder Decoder
62
+ ┌──────────┐ LT Fountain ┌──────────┐ Screen cap ┌──────────┐ QR detect ┌──────────┐
63
+ │ File │ ────────────── → │ QR Video │ ──────────── → │ Video │ ────────────→ │ Recovered│
64
+ └──────────┘ zlib + COBS └──────────┘ └──────────┘ LT decode │ File │
65
+ └──────────┘
66
+ ```
67
+
68
+ 1. **Encode**: Split the file (optionally zlib-compressed) into blocks, generate redundant coded blocks via LT fountain codes, serialize each into a V3 protocol frame, COBS-encode, embed into QR codes, and output an MP4 video.
69
+ 2. **Decode**: Extract QR codes from video using WeChatQRCode (highly robust), COBS-decode, CRC32-validate to discard corrupted frames, feed into the LT decoder for belief propagation (peeling), and reconstruct the original file. The decoder auto-detects V2/V3 protocols.
70
+
71
+ **Key Features**:
72
+ - **LT Fountain Codes**: Rateless erasure codes — naturally tolerant of frame loss, blur, and occlusion
73
+ - **COBS Encoding**: Only ~0.4% overhead, saves 33% capacity compared to base64
74
+ - **WeChatQRCode Detector**: Far more robust than standard QR detectors for phone-captured screens (perspective, moire, lighting)
75
+ - **Adaptive Sample Rate**: Automatically selects optimal sampling strategy based on detection rate and frame repetition
76
+ - **Targeted Recovery**: After initial scan, precisely re-scans video segments where missing blocks are expected
77
+ - **Low-Memory Paths**: mmap-backed encoding and streaming decode-to-file for large inputs
78
+
79
+ ## Installation
80
+
81
+ ### From PyPI with pip
82
+
83
+ ```bash
84
+ pip install qrstream
85
+ ```
86
+
87
+ Use either command after installation:
88
+
89
+ ```bash
90
+ qrstream <command> [options]
91
+ # or
92
+ qrs <command> [options]
93
+ ```
94
+
95
+ You can also run it as a module:
96
+
97
+ ```bash
98
+ python -m qrstream <command> [options]
99
+ ```
100
+
101
+ ### From PyPI with uv
102
+
103
+ ```bash
104
+ uv tool install qrstream
105
+ ```
106
+
107
+ Then run:
108
+
109
+ ```bash
110
+ qrstream <command> [options]
111
+ ```
112
+
113
+ For one-off execution without a persistent install:
114
+
115
+ ```bash
116
+ uvx qrstream <command> [options]
117
+ ```
118
+
119
+ ### Development Install
120
+
121
+ ```bash
122
+ git clone https://github.com/ddddavid-he/qrstream-enhanced.git && cd qrstream-enhanced
123
+ uv sync --dev
124
+ ```
125
+
126
+ ### Requirements
127
+
128
+ - Python >= 3.10
129
+ - Dependencies: `opencv-contrib-python`, `numpy`, `tqdm`, `qrcode[pil]`
130
+
131
+ ## Usage
132
+
133
+ ```bash
134
+ qrstream <command> [options]
135
+ ```
136
+
137
+ `qrs` is kept as a short alias, and `python -m qrstream` works as well.
138
+
139
+ ### Encode (File → QR Video)
140
+
141
+ ```bash
142
+ qrstream encode <file> -o output.mp4 [options]
143
+ ```
144
+
145
+ | Option | Default | Description |
146
+ |--------|---------|-------------|
147
+ | `<file>` | - | Input file path |
148
+ | `-o, --output` | `<filename>.mp4` | Output video path |
149
+ | `--overhead` | `2.0` | Encoding redundancy ratio (multiple of source block count) |
150
+ | `--fps` | `10` | Output video frame rate |
151
+ | `--ec-level` | `1` | QR error correction: 0=L(7%), 1=M(15%), 2=Q(25%), 3=H(30%) |
152
+ | `--qr-version` | `20` | QR code version 1-40 (higher = denser) |
153
+ | `--no-compress` | - | Disable zlib compression |
154
+ | `--force-compress` | - | Force compression for large V3 inputs (higher memory usage) |
155
+ | `--base64-qr` | - | Use base64 encoding instead of COBS (better compat, 33% less capacity) |
156
+ | `--legacy-qr` | - | Use `qrcode` library for QR generation (slower, finer control) |
157
+ | `--codec` | `mp4v` | Video codec: `mp4v` or `mjpeg` (faster but larger files) |
158
+ | `--protocol` | `v3` | Protocol version: `v3` (default) or `v2` |
159
+ | `-w, --workers` | CPU count | Parallel workers for QR generation |
160
+ | `-v, --verbose` | - | Print extra detail (progress bars always shown) |
161
+
162
+ ### Decode (QR Video → File)
163
+
164
+ ```bash
165
+ qrstream decode <video> -o output_file [options]
166
+ ```
167
+
168
+ | Option | Default | Description |
169
+ |--------|---------|-------------|
170
+ | `<video>` | - | Input video path (MP4, MOV, etc.) |
171
+ | `-o, --output` | `decoded_output` | Output file path |
172
+ | `-s, --sample-rate` | `0` (auto) | Sample every Nth frame (0 = adaptive probing) |
173
+ | `-w, --workers` | All CPU cores | Parallel workers for QR detection |
174
+ | `-v, --verbose` | - | Print detailed progress |
175
+
176
+ ### Examples
177
+
178
+ ```bash
179
+ # Encode a PDF (default: COBS binary mode, 2x redundancy)
180
+ qrstream encode report.pdf -o report.mp4 --overhead 2.0 -v
181
+
182
+ # Decode video (adaptive sample rate + targeted recovery)
183
+ qrstream decode report.mp4 -o report_recovered.pdf -v
184
+
185
+ # Encode with high error correction (for phone screen capture)
186
+ qrstream encode data.bin -o data.mp4 --ec-level 3 --qr-version 15
187
+ ```
188
+
189
+ ### Python API
190
+
191
+ ```python
192
+ from qrstream.encoder import encode_to_video
193
+ from qrstream.decoder import extract_qr_from_video, decode_blocks, decode_blocks_to_file
194
+
195
+ # Encode (default: COBS binary mode)
196
+ encode_to_video("input.bin", "output.mp4", overhead=2.0, verbose=True)
197
+
198
+ # Decode to memory
199
+ blocks = extract_qr_from_video("output.mp4", verbose=True)
200
+ result = decode_blocks(blocks, verbose=True)
201
+
202
+ # Better for large files: stream directly to file with incremental decompression
203
+ written = decode_blocks_to_file(blocks, "recovered.bin", verbose=True)
204
+ print(f"wrote {written} bytes")
205
+ ```
206
+
207
+ ## Project Structure
208
+
209
+ ```
210
+ project-root/
211
+ ├── pyproject.toml # Project config & dependencies
212
+ ├── src/qrstream/
213
+ │ ├── cli.py # CLI entry (encode/decode subcommands)
214
+ │ ├── encoder.py # LT encode → QR frame generation → MP4 video
215
+ │ ├── decoder.py # Video frame extraction → QR detect → LT decode → file rebuild
216
+ │ ├── lt_codec.py # LT fountain code primitives (PRNG, RSD, BlockGraph)
217
+ │ ├── protocol.py # V2/V3 protocol serialization + COBS codec
218
+ │ └── qr_utils.py # QR generation (OpenCV) + detection (WeChatQRCode)
219
+ ├── tests/
220
+ │ ├── test_lt_codec.py # LT codec unit tests
221
+ │ ├── test_protocol.py # V2/V3 protocol + COBS tests
222
+ │ ├── test_decoder.py # Decoder validation + probe strategy tests
223
+ │ ├── test_roundtrip.py # End-to-end roundtrip tests
224
+ │ └── test_optimizations.py # Perf optimizations + WeChatQR + COBS tests
225
+ └── benchmarks/
226
+ └── benchmark.py # Performance benchmarks
227
+ ```
228
+
229
+ ## Technical Details
230
+
231
+ ### V3 Protocol Format (24-byte header + 4-byte trailing CRC)
232
+
233
+ ```
234
+ Offset Size Field
235
+ 0 1 version 0x03
236
+ 1 1 flags bit0=zlib compressed, bit1=COBS binary mode
237
+ 2 8 filesize uint64 BE (encoded payload size; compressed size when zlib is on)
238
+ 10 2 blocksize uint16 BE
239
+ 12 4 block_count uint32 BE K = ceil(filesize / blocksize)
240
+ 16 4 seed uint32 BE PRNG seed
241
+ 20 2 block_seq uint16 BE monotonically increasing sequence number
242
+ 22 2 reserved reserved (currently 0)
243
+ 24 ... data blocksize bytes of encoded data
244
+ ... 4 crc32 CRC32(header[0:24] + data)
245
+ ```
246
+
247
+ - Default encoding uses **V3**.
248
+ - The decoder auto-detects **V2** and **V3**.
249
+ - V3 extends `filesize` to `uint64` and `block_count` to `uint32`, supporting larger files and block counts.
250
+
251
+ ### Encoding Modes
252
+
253
+ | Mode | QR Content | Capacity Overhead | Default |
254
+ |------|-----------|-------------------|---------|
255
+ | COBS binary | raw bytes → COBS → latin-1 string | ~0.4% | Yes |
256
+ | Base64 | raw bytes → base64 string | ~33% | No (`--base64-qr`) |
257
+
258
+ COBS (Consistent Overhead Byte Stuffing) eliminates all `\x00` bytes, allowing binary data to safely pass through QR string interfaces.
259
+
260
+ ### Large Files & Low-Memory Paths
261
+
262
+ - For large **V3** inputs, the encoder uses `mmap` for random access, avoiding loading the entire file into memory.
263
+ - When the input is large enough, V3 encoding automatically disables `zlib` compression to preserve the low-memory path; use `--force-compress` to override.
264
+ - The decoder supports streaming writes with incremental decompression, reducing memory overhead.
265
+ - Large file decoding shows **LT block decoding progress** and **output write progress** bars.
266
+
267
+ ### Decoding Pipeline
268
+
269
+ 1. **Probe phase**: Sample 3 spread-out windows in the video (120 frames each by default), measure detection rate and repetition per window, pick the most conservative `sample_rate`
270
+ 2. **Main scan**: Detect QR codes in parallel at the adaptive sample rate, feeding into the LT decoder in real time
271
+ 3. **Targeted recovery**: If the first pass didn't recover all blocks, use linear regression on observed (seed, frame) pairs to locate missing seeds and re-scan those segments precisely
272
+ 4. **LT decode**: Belief propagation (peeling) to recover all source blocks
273
+ 5. **Output writeback**: Write recovered blocks sequentially; incremental decompression in compressed mode
274
+
275
+ ### LT Fountain Code Parameters
276
+
277
+ | Parameter | Value | Notes |
278
+ |-----------|-------|-------|
279
+ | Degree distribution | Robust Soliton Distribution | c=0.1, delta=0.5 |
280
+ | PRNG | LCG (a=16807, m=2^31-1) | 5 warmup rounds to eliminate sequential seed bias |
281
+ | XOR | numpy vectorized + in-place | 10-50x faster than pure Python |
282
+ | Decoding | Belief Propagation (Peeling) | Iterative elimination on bipartite graph |
283
+
284
+ ## Testing
285
+
286
+ ```bash
287
+ uv run pytest tests/ -v
288
+ ```
289
+
290
+ ## License
291
+
292
+ MIT
@@ -0,0 +1,238 @@
1
+ # QRStream
2
+
3
+ [English](README.md)
4
+
5
+ 通过 QR 码视频流传输任意文件。基于 **LT 喷泉码(Luby Transform Fountain Codes)** 实现可靠的无反馈信道数据传输——即使丢失部分帧也能完整恢复原始文件。
6
+
7
+ ## 原理概览
8
+
9
+ ```
10
+ 编码端 解码端
11
+ ┌──────────┐ LT 喷泉码 ┌──────────┐ 录屏/拍摄 ┌──────────┐ QR 识别 ┌──────────┐
12
+ │ 原始文件 │ ──────────── → │ QR 码视频 │ ──────────→ │ 视频文件 │ ──────────→ │ 还原文件 │
13
+ └──────────┘ zlib + COBS └──────────┘ └──────────┘ LT 解码 └──────────┘
14
+ ```
15
+
16
+ 1. **编码**:将文件(可选 zlib 压缩)分块,通过 LT 喷泉码生成冗余编码块,每块序列化为 V3 协议帧,经 COBS 编码后嵌入 QR 码,最终输出 MP4 视频。
17
+ 2. **解码**:使用 WeChatQRCode 从视频中高鲁棒性地提取 QR 码,COBS 解码后 CRC32 校验去除损坏帧,喂入 LT 解码器进行信念传播(peeling),恢复所有源块后重建原始文件。解码端会自动兼容 V2/V3 协议。
18
+
19
+ **核心优势**:
20
+ - **LT 喷泉码**:无码率纠删码,天然容忍帧丢失、模糊、遮挡
21
+ - **COBS 编码**:仅 0.4% overhead,比 base64 节省 33% 容量
22
+ - **WeChatQRCode 检测器**:对手机拍摄场景(透视、摩尔纹、光照)鲁棒性远超标准 QR 检测器
23
+ - **自适应采样率**:根据检测率和帧重复数自动选择最优采样策略
24
+ - **定向恢复**:首轮扫描后针对缺失块的时间位置精准补扫
25
+
26
+ ## 安装
27
+
28
+ ### 通过 pip 从 PyPI 安装
29
+
30
+ ```bash
31
+ pip install qrstream
32
+ ```
33
+
34
+ 安装后可直接使用以下任一命令:
35
+
36
+ ```bash
37
+ qrstream <command> [options]
38
+ # 或
39
+ qrs <command> [options]
40
+ ```
41
+
42
+ 也可以通过模块方式运行:
43
+
44
+ ```bash
45
+ python -m qrstream <command> [options]
46
+ ```
47
+
48
+ ### 通过 uv 从 PyPI 安装
49
+
50
+ ```bash
51
+ uv tool install qrstream
52
+ ```
53
+
54
+ 安装后运行:
55
+
56
+ ```bash
57
+ qrstream <command> [options]
58
+ ```
59
+
60
+ 如果只想临时执行而不常驻安装:
61
+
62
+ ```bash
63
+ uvx qrstream <command> [options]
64
+ ```
65
+
66
+ ### 开发环境安装
67
+
68
+ ```bash
69
+ git clone https://github.com/ddddavid-he/qrstream-enhanced.git && cd qrstream-enhanced
70
+ uv sync --dev
71
+ ```
72
+
73
+ ### 系统要求
74
+
75
+ - Python >= 3.10
76
+ - 依赖:`opencv-contrib-python`, `numpy`, `tqdm`, `qrcode[pil]`
77
+
78
+ ## 使用方式
79
+
80
+ ```bash
81
+ qrstream <command> [options]
82
+ ```
83
+
84
+ 同时保留 `qrs` 这个短命令别名,也支持 `python -m qrstream`。
85
+
86
+ ### 编码(文件 → QR 码视频)
87
+
88
+ ```bash
89
+ qrstream encode <file> -o output.mp4 [options]
90
+ ```
91
+
92
+ | 参数 | 默认值 | 说明 |
93
+ |------|--------|------|
94
+ | `<file>` | - | 输入文件路径 |
95
+ | `-o, --output` | `<filename>.mp4` | 输出视频路径 |
96
+ | `--overhead` | `2.0` | 编码冗余倍率(源块数的倍数) |
97
+ | `--fps` | `10` | 输出视频帧率 |
98
+ | `--ec-level` | `1` | QR 纠错等级:0=L(7%), 1=M(15%), 2=Q(25%), 3=H(30%) |
99
+ | `--qr-version` | `20` | QR 码版本 1-40(越大密度越高) |
100
+ | `--no-compress` | - | 禁用 zlib 压缩 |
101
+ | `--force-compress` | - | 对大文件的 V3 编码强制整体压缩(会占用更多内存) |
102
+ | `--base64-qr` | - | 使用 base64 编码代替 COBS(兼容性更好但容量少 33%) |
103
+ | `--legacy-qr` | - | 使用 qrcode 库生成 QR(更慢但参数控制更精细) |
104
+ | `--codec` | `mp4v` | 视频编码器:`mp4v` 或 `mjpeg`(更快但文件更大) |
105
+ | `--protocol` | `v3` | 编码协议版本:`v3`(默认)或 `v2` |
106
+ | `-w, --workers` | CPU 核心数 | 并行 QR 生成的工作进程数 |
107
+ | `-v, --verbose` | - | 输出额外详细信息(进度条始终显示) |
108
+
109
+ ### 解码(QR 码视频 → 文件)
110
+
111
+ ```bash
112
+ qrstream decode <video> -o output_file [options]
113
+ ```
114
+
115
+ | 参数 | 默认值 | 说明 |
116
+ |------|--------|------|
117
+ | `<video>` | - | 输入视频路径(MP4, MOV 等) |
118
+ | `-o, --output` | `decoded_output` | 输出文件路径 |
119
+ | `-s, --sample-rate` | `0`(自动) | 每 N 帧采样一次(0=自适应探测) |
120
+ | `-w, --workers` | 全部 CPU 核心 | 并行 QR 识别的工作进程数 |
121
+ | `-v, --verbose` | - | 输出详细进度信息;大任务会显示 probe、扫描、LT 解码和写文件进度 |
122
+
123
+ ### 示例
124
+
125
+ ```bash
126
+ # 编码 PDF 文件(默认 COBS 二进制模式,2 倍冗余)
127
+ qrstream encode report.pdf -o report.mp4 --overhead 2.0 -v
128
+
129
+ # 解码视频(自适应采样率 + 定向恢复)
130
+ qrstream decode report.mp4 -o report_recovered.pdf -v
131
+
132
+ # 编码时使用高纠错等级(适合手机拍屏场景)
133
+ qrstream encode data.bin -o data.mp4 --ec-level 3 --qr-version 15
134
+ ```
135
+
136
+ ### 编程接口
137
+
138
+ ```python
139
+ from qrstream.encoder import encode_to_video
140
+ from qrstream.decoder import extract_qr_from_video, decode_blocks, decode_blocks_to_file
141
+
142
+ # 编码(默认使用 COBS 二进制模式)
143
+ encode_to_video("input.bin", "output.mp4", overhead=2.0, verbose=True)
144
+
145
+ # 解码到内存
146
+ blocks = extract_qr_from_video("output.mp4", verbose=True)
147
+ result = decode_blocks(blocks, verbose=True)
148
+
149
+ # 更适合大文件:直接写文件,降低额外内存占用
150
+ written = decode_blocks_to_file(blocks, "recovered.bin", verbose=True)
151
+ print(f"wrote {written} bytes")
152
+ ```
153
+
154
+ ## 项目结构
155
+
156
+ ```
157
+ project-root/
158
+ ├── pyproject.toml # 项目配置与依赖
159
+ ├── src/qrstream/
160
+ │ ├── cli.py # CLI 入口(encode/decode 子命令)
161
+ │ ├── encoder.py # LT 编码 → QR 帧生成 → MP4 视频写入
162
+ │ ├── decoder.py # 视频帧提取 → QR 检测 → LT 解码 → 文件重建
163
+ │ ├── lt_codec.py # LT 喷泉码原语(PRNG、RSD、BlockGraph)
164
+ │ ├── protocol.py # V2/V3 协议序列化 + COBS 编解码
165
+ │ └── qr_utils.py # QR 生成(OpenCV)+ 检测(WeChatQRCode)
166
+ ├── tests/
167
+ │ ├── test_lt_codec.py # LT 编解码器单元测试
168
+ │ ├── test_protocol.py # V2/V3 协议 + COBS 测试
169
+ │ ├── test_roundtrip.py # 端到端回环测试
170
+ │ └── test_optimizations.py # 性能优化 + WeChatQR + COBS 测试
171
+ └── benchmarks/
172
+ └── benchmark.py # 性能基准测试
173
+ ```
174
+
175
+ ## 技术细节
176
+
177
+ ### V3 协议格式(24 字节头部 + 4 字节尾部 CRC)
178
+
179
+ ```
180
+ Offset Size Field
181
+ 0 1 version 0x03
182
+ 1 1 flags bit0=zlib 压缩, bit1=COBS 二进制模式
183
+ 2 8 filesize uint64 BE(编码载荷大小;压缩时为压缩后大小)
184
+ 10 2 blocksize uint16 BE
185
+ 12 4 block_count uint32 BE K = ceil(filesize / blocksize)
186
+ 16 4 seed uint32 BE PRNG 种子
187
+ 20 2 block_seq uint16 BE 单调递增序号
188
+ 22 2 reserved 预留(当前为 0)
189
+ 24 ... data blocksize 字节的编码数据
190
+ ... 4 crc32 CRC32(header[0:24] + data)
191
+ ```
192
+
193
+ - 默认编码使用 **V3**。
194
+ - 解码器会自动兼容 **V2** 和 **V3**。
195
+ - V3 将 `filesize` 扩展为 `uint64`,`block_count` 扩展为 `uint32`,适合更大的文件和块数。
196
+
197
+ ### 编码模式
198
+
199
+ | 模式 | QR 内容 | 容量开销 | 默认 |
200
+ |------|---------|----------|------|
201
+ | COBS 二进制 | raw bytes → COBS → latin-1 string | ~0.4% | 是 |
202
+ | Base64 | raw bytes → base64 string | ~33% | 否(`--base64-qr`) |
203
+
204
+ COBS(Consistent Overhead Byte Stuffing)消除所有 `\x00` 字节,使数据可安全通过 QR 字符串接口传递。
205
+
206
+ ### 大文件与低内存路径
207
+
208
+ - 对于较大的 **V3** 输入文件,编码端会优先使用 `mmap` 做随机访问,避免把原文件整体复制进内存。
209
+ - 当输入足够大时,V3 编码默认会关闭整体 `zlib` 压缩,以保留低内存路径;如需强制压缩可使用 `--force-compress`。
210
+ - 解码端在恢复完成后支持直接写文件,并在压缩模式下使用增量解压,降低额外内存占用。
211
+ - 大文件解码会额外显示 **LT block 解码进度** 和 **输出写入进度**,避免在提取 QR 完成后长时间无输出。
212
+
213
+ ### 解码管线
214
+
215
+ 1. **探测阶段**:在视频中段的 3 个分散窗口中采样(默认每窗 120 帧),分别测量检测率和重复度,并取最保守的 `sample_rate`
216
+ 2. **主扫描**:按自适应采样率并行检测 QR 码,实时喂入 LT 解码器
217
+ 3. **定向恢复**:若首轮未恢复完整,定位缺失 seed 对应的视频时间段精准补扫
218
+ 4. **LT 解码**:信念传播(peeling)算法恢复所有源块,并对大任务显示 block 解码进度
219
+ 5. **输出写回**:按序写回恢复块;压缩模式下使用增量解压,并显示写文件进度
220
+
221
+ ### LT 喷泉码参数
222
+
223
+ | 参数 | 值 | 说明 |
224
+ |------|-----|------|
225
+ | 度分布 | Robust Soliton Distribution | c=0.1, delta=0.5 |
226
+ | PRNG | LCG (a=16807, m=2^31-1) | 5 轮预热消除序列种子偏差 |
227
+ | XOR | numpy 向量化 + 原地操作 | 比纯 Python 快 10-50x |
228
+ | 解码 | Belief Propagation (Peeling) | 基于二部图的迭代消元 |
229
+
230
+ ## 测试
231
+
232
+ ```bash
233
+ uv run pytest tests/ -v
234
+ ```
235
+
236
+ ## 许可证
237
+
238
+ MIT