klartext 1.0.0__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.
- klartext-1.0.0/LICENSE +21 -0
- klartext-1.0.0/PKG-INFO +565 -0
- klartext-1.0.0/README.md +517 -0
- klartext-1.0.0/klartext/__init__.py +7 -0
- klartext-1.0.0/klartext/__main__.py +5 -0
- klartext-1.0.0/klartext/cli.py +1008 -0
- klartext-1.0.0/klartext/core.py +307 -0
- klartext-1.0.0/klartext/decoders/__init__.py +55 -0
- klartext-1.0.0/klartext/decoders/audi_mib4.py +402 -0
- klartext-1.0.0/klartext/decoders/base.py +62 -0
- klartext-1.0.0/klartext/exporters/__init__.py +18 -0
- klartext-1.0.0/klartext/exporters/ass_exporter.py +109 -0
- klartext-1.0.0/klartext/exporters/csv_exporter.py +64 -0
- klartext-1.0.0/klartext/exporters/ffmeta.py +120 -0
- klartext-1.0.0/klartext/exporters/gpx_exporter.py +49 -0
- klartext-1.0.0/klartext/exporters/html_map.py +437 -0
- klartext-1.0.0/klartext/exporters/json_exporter.py +50 -0
- klartext-1.0.0/klartext/ffmpeg_tools.py +126 -0
- klartext-1.0.0/klartext/renderers/__init__.py +6 -0
- klartext-1.0.0/klartext/renderers/compositor.py +218 -0
- klartext-1.0.0/klartext/renderers/hud_pil.py +706 -0
- klartext-1.0.0/klartext/tiles.py +365 -0
- klartext-1.0.0/klartext.egg-info/PKG-INFO +565 -0
- klartext-1.0.0/klartext.egg-info/SOURCES.txt +28 -0
- klartext-1.0.0/klartext.egg-info/dependency_links.txt +1 -0
- klartext-1.0.0/klartext.egg-info/entry_points.txt +2 -0
- klartext-1.0.0/klartext.egg-info/requires.txt +8 -0
- klartext-1.0.0/klartext.egg-info/top_level.txt +1 -0
- klartext-1.0.0/pyproject.toml +63 -0
- klartext-1.0.0/setup.cfg +4 -0
klartext-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OGMatrix
|
|
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.
|
klartext-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: klartext
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Decode dashcam telemetry from cars like Audi A5 (E3 1.2 / MIB4) and burn an in-car-style HUD
|
|
5
|
+
Author-email: OGMatrix <matrix@ogmatrix.net>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 OGMatrix
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/OGMatrix/klartext
|
|
29
|
+
Project-URL: Repository, https://github.com/OGMatrix/klartext
|
|
30
|
+
Project-URL: Issues, https://github.com/OGMatrix/klartext/issues
|
|
31
|
+
Project-URL: Changelog, https://github.com/OGMatrix/klartext/blob/main/CHANGELOG.md
|
|
32
|
+
Keywords: audi,dashcam,telemetry,hud,gps,video
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Environment :: Console
|
|
37
|
+
Classifier: Topic :: Multimedia :: Video
|
|
38
|
+
Requires-Python: >=3.8
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE
|
|
41
|
+
Requires-Dist: rich>=13.0
|
|
42
|
+
Provides-Extra: hud
|
|
43
|
+
Requires-Dist: Pillow>=10.0; extra == "hud"
|
|
44
|
+
Provides-Extra: full
|
|
45
|
+
Requires-Dist: Pillow>=10.0; extra == "full"
|
|
46
|
+
Requires-Dist: cairosvg>=2.5; extra == "full"
|
|
47
|
+
Dynamic: license-file
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<picture>
|
|
51
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/klartext-primary-dark.svg">
|
|
52
|
+
<img src="assets/klartext-primary.svg" alt="klartext" width="440">
|
|
53
|
+
</picture>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<em>Decode the hidden telemetry your dashcam was silently recording.</em>
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
<p align="center">
|
|
61
|
+
<!-- x-release-please-start-version -->
|
|
62
|
+
<a href="https://github.com/OGMatrix/klartext/releases/tag/v1.0.0"><img src="https://img.shields.io/badge/version-1.0.0-ff8800?style=flat-square" alt="v1.0.0"></a>
|
|
63
|
+
<!-- x-release-please-end -->
|
|
64
|
+
|
|
65
|
+
<img src="https://img.shields.io/badge/python-3.8+-3776ab?style=flat-square" alt="Python 3.8+">
|
|
66
|
+
|
|
67
|
+
<img src="https://img.shields.io/badge/license-MIT-22c55e?style=flat-square" alt="MIT">
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
<p align="center">
|
|
71
|
+
<code>offline</code> <code>open-source</code> <code>multi-format decoder</code> <code>HUD compositor</code>
|
|
72
|
+
</p>
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
**klartext** (German: *plain text; speaking the unvarnished truth*) is a command-line tool that decodes the telemetry stream embedded in dashcam footage and renders a clean HUD overlay onto a copy of the video.
|
|
77
|
+
|
|
78
|
+
The goal is **universal**: any dashcam that hides or embeds telemetry — protobuf cues, NMEA sentences, GoPro GPMF, manufacturer-proprietary binary, plain-text subtitle GPS — should be readable through klartext.
|
|
79
|
+
|
|
80
|
+
The reality today is **one format**: the Audi A5 (2026, E3 1.2 / MIB4) protobuf-in-`tx3g` payload that the project was originally built around. The architecture treats this as one decoder among many; new formats live behind the same pipeline. See [04 / Supported Cameras](#04--supported-cameras) for the current matrix, and [09 / Roadmap](#09--roadmap) for what's next.
|
|
81
|
+
|
|
82
|
+
Everything happens on your machine. No cloud, no accounts, no telemetry of its own.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
<p align="center">
|
|
87
|
+
<video src="https://github.com/OGMatrix/klartext/releases/download/v1.0.0/2026-05-14_15-57-58.hud.mp4"
|
|
88
|
+
controls muted playsinline autoplay width="100%">
|
|
89
|
+
</video>
|
|
90
|
+
</p>
|
|
91
|
+
|
|
92
|
+
<p align="center"><em>Audi A5 (2026) — HUD rendered by klartext from the embedded telemetry track</em></p>
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Contents
|
|
97
|
+
|
|
98
|
+
- [01 / Overview](#01--overview)
|
|
99
|
+
- [02 / Quick Start](#02--quick-start)
|
|
100
|
+
- [03 / Output](#03--output)
|
|
101
|
+
- [04 / Supported Cameras](#04--supported-cameras)
|
|
102
|
+
- [05 / How It Works](#05--how-it-works)
|
|
103
|
+
- [06 / Telemetry Field Reference](#06--telemetry-field-reference)
|
|
104
|
+
- [07 / CLI Reference](#07--cli-reference)
|
|
105
|
+
- [08 / Watermark Policy](#08--watermark-policy)
|
|
106
|
+
- [09 / Roadmap](#09--roadmap)
|
|
107
|
+
- [10 / Contributing](#10--contributing)
|
|
108
|
+
- [11 / License](#11--license)
|
|
109
|
+
- [12 / Acknowledgements](#12--acknowledgements)
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 01 / Overview
|
|
114
|
+
|
|
115
|
+
klartext is two pieces glued together:
|
|
116
|
+
|
|
117
|
+
1. **A decoder** that reads telemetry from whatever the camera embedded — and normalises it into a universal frame format with timestamp, GPS, speed, heading, odometer, optional altitude, plus a typed bag of vendor-specific extras.
|
|
118
|
+
2. **A renderer** that turns those frames into standard outputs (CSV, JSON, GPX) and a clean HUD overlay on a re-encoded copy of the video — Audi-MMI-style by default, configurable.
|
|
119
|
+
|
|
120
|
+
The decoder is the part that varies between camera vendors. The renderer is the part that doesn't. Everything between the two — the universal `KSFFrame` / `KSFDocument`, the writers, the encoder picker, the HUD layout, the watermark, the minimap — is shared across formats.
|
|
121
|
+
|
|
122
|
+
Today klartext ships with **one decoder**: the Audi A5 (E3 1.2 / MIB4) protobuf-in-`tx3g` format. New decoders are added by **opening an issue with a sample clip** from a format klartext can't read yet — the maintainers handle the decoder work. You don't have to write code; you just have to bring the data. (Writing the decoder yourself is welcome too, but optional.) The workflow is in [`CONTRIBUTING.md`](./CONTRIBUTING.md#05--adding-a-new-decoder-format).
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 02 / Quick Start
|
|
127
|
+
|
|
128
|
+
### Requirements
|
|
129
|
+
|
|
130
|
+
| Component | Version | Required? | Notes |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| Python | ≥ 3.8 | yes | type-hinted dataclasses |
|
|
133
|
+
| ffmpeg / ffprobe | ≥ 5.0 | yes | must be on `$PATH` |
|
|
134
|
+
| `rich` | latest | yes | terminal UI |
|
|
135
|
+
| `Pillow` | ≥ 10.0 | optional | enables the graphical HUD with minimap. Without it, klartext falls back to ASS subtitle overlay. |
|
|
136
|
+
|
|
137
|
+
Hardware-accelerated encoding is auto-detected in this order: NVIDIA NVENC → Intel QSV → AMD/Mesa VAAPI → `libx265` software. Override with `--encoder` if needed.
|
|
138
|
+
|
|
139
|
+
### Installation
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# recommended (includes Pillow for the graphical HUD):
|
|
143
|
+
pip install "klartext[hud]"
|
|
144
|
+
|
|
145
|
+
# minimal (no graphical HUD, ASS subtitle overlay only):
|
|
146
|
+
pip install klartext
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# or install from source (latest unreleased commit):
|
|
151
|
+
git clone https://github.com/OGMatrix/klartext
|
|
152
|
+
cd klartext
|
|
153
|
+
pip install -e ".[hud]"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`Pillow` is optional but strongly recommended — it enables the full graphical HUD with satellite minimap and brand mark. Without it, klartext falls back to an ASS subtitle overlay only.
|
|
157
|
+
|
|
158
|
+
### Run
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
klartext drive.mp4
|
|
162
|
+
# or equivalently:
|
|
163
|
+
python -m klartext drive.mp4
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
That is the entire common case. By default klartext writes its outputs next to the input file.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
klartext --version
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Reports the current version.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 03 / Output
|
|
177
|
+
|
|
178
|
+
For an input `drive.mp4`, klartext produces:
|
|
179
|
+
|
|
180
|
+
| File | Format | Purpose |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `drive.telemetry.csv` | wide CSV | one row per cue, every decoded field |
|
|
183
|
+
| `drive.telemetry.json` | structured JSON | scripting / pipeline use, includes raw fields |
|
|
184
|
+
| `drive.track.gpx` | GPX 1.1 | drop into any mapping tool |
|
|
185
|
+
| `drive.hud.ass` | Advanced SubStation Alpha | the overlay subtitle, re-usable on its own |
|
|
186
|
+
| `drive.hud.mp4` | HEVC video | re-encoded with the HUD burned in |
|
|
187
|
+
| `drive.map.html` | HTML | self-contained Leaflet.js interactive route viewer (opt-in: `--html-map`) |
|
|
188
|
+
| `drive.chapters.ffmeta` | FFMETADATA | chapter markers injected during re-encode (opt-in: `--chapters`) |
|
|
189
|
+
| `drive.thumb.jpg` | JPEG | HUD-composited still thumbnail at a chosen timestamp (opt-in: `--thumbnail`) |
|
|
190
|
+
|
|
191
|
+
The CSV columns map directly to the fields in [06 / Telemetry Field Reference](#06--telemetry-field-reference).
|
|
192
|
+
|
|
193
|
+
The GPX file includes klartext-specific extensions for the fields GPX 1.1 doesn't natively carry (cumulative odometer, GPS C/N₀) — readable by any GPX-aware tool, with the extras ignored cleanly.
|
|
194
|
+
|
|
195
|
+
If `Pillow` is installed, the burned-in HUD includes a satellite minimap with a heading-aware GPS marker, the date/time + location panel, a centred speed readout, and a small klartext mark in the lower-right corner. Without `Pillow`, the same telemetry is shown via the ASS subtitle overlay, minus the minimap.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 04 / Supported Cameras
|
|
200
|
+
|
|
201
|
+
Two axes: the **telemetry format** (what protocol klartext reads), and the **specific hardware** known to use that format. Adding a new vehicle to an already-supported format is usually a one-line change; adding a new format is a new decoder module.
|
|
202
|
+
|
|
203
|
+
### Telemetry formats
|
|
204
|
+
|
|
205
|
+
Status legend: **Working** = first-class support; **Planned** = committed roadmap item with a defined approach; **In investigation** = format identified, feasibility being assessed.
|
|
206
|
+
|
|
207
|
+
| Format | Vendors / cameras it covers | Status | Difficulty |
|
|
208
|
+
|---|---|---|---|
|
|
209
|
+
| Audi protobuf-in-`tx3g` | Audi A5 (2026), likely Q6 e-tron, A6 e-tron, Porsche Macan EV — all E3 1.2 / MIB4 | Working | reverse-engineered |
|
|
210
|
+
| GoPro GPMF (`gpmd` metadata track) | GoPro Hero 5+, some Insta360, Sony Action Cam | Planned | well-documented public spec |
|
|
211
|
+
| DJI SRT subtitle GPS | DJI Mavic / Air / Mini, Osmo Action | Planned | plain text, regex-extractable |
|
|
212
|
+
| NMEA 0183 sidecar | Garmin, Viofo, Thinkware, Nextbase, some BlackVue | Planned | standard GPS protocol |
|
|
213
|
+
| Novatek embedded | Viofo A119, generic Novatek-chipset cams | In investigation | community-RE'd binary atom |
|
|
214
|
+
| BMW integrated dashcam | recent BMW models with built-in cam | In investigation | format undocumented |
|
|
215
|
+
| Mercedes integrated dashcam | recent MBUX-based models with built-in cam | In investigation | format undocumented |
|
|
216
|
+
| Tesla TeslaCam | Tesla Model S/3/X/Y | In investigation | GPS is in vehicle logs, not the clip — feasibility uncertain |
|
|
217
|
+
|
|
218
|
+
### Verified hardware
|
|
219
|
+
|
|
220
|
+
Specific cameras / vehicles confirmed working through actual sample testing.
|
|
221
|
+
|
|
222
|
+
| Manufacturer | Model | Year | Format | Status | Verified by |
|
|
223
|
+
|---|---|---|---|---|---|
|
|
224
|
+
| Audi | A5 | 2026 | Audi protobuf-in-`tx3g` | Working | project author |
|
|
225
|
+
|
|
226
|
+
*"Working" means: the telemetry stream is detected, every sample parses cleanly, GPS + speed + odometer round-trip correctly, and the rendered HUD matches the in-car (or expected) playback.*
|
|
227
|
+
|
|
228
|
+
### Likely compatible — testing welcome
|
|
229
|
+
|
|
230
|
+
Other vehicles built on the **Volkswagen Group E3 1.2 / MIB4** platform with an integrated dashcam are expected to use the same protobuf schema. Candidates, in rough order of confidence:
|
|
231
|
+
|
|
232
|
+
- Audi Q6 e-tron (2025+)
|
|
233
|
+
- Audi A6 e-tron (2025+)
|
|
234
|
+
- Audi A6 (current generation)
|
|
235
|
+
- Audi Q5 (next generation)
|
|
236
|
+
- Porsche Macan EV (2024+)
|
|
237
|
+
|
|
238
|
+
If you own one of these and have a dashcam export to share, please open an issue — your sample is what moves the row from this list to the verified table.
|
|
239
|
+
|
|
240
|
+
### Adding to either table
|
|
241
|
+
|
|
242
|
+
Both paths are issue-driven and primarily about *you bringing the data*. You don't need to write code. Open an issue with a sample clip, the `ffprobe` output, and whatever else you can find (camera model, firmware, sidecar files, manufacturer docs), and the maintainers will handle the decoder work. Writing the decoder yourself is welcome but optional.
|
|
243
|
+
|
|
244
|
+
- **New hardware on an existing format** (e.g., another E3 1.2 Audi): see [`CONTRIBUTING.md`](./CONTRIBUTING.md#04--adding-a-new-vehicle-to-an-existing-format).
|
|
245
|
+
- **New format entirely** (e.g., a NMEA-sidecar dashcam, a GoPro export): see [`CONTRIBUTING.md`](./CONTRIBUTING.md#05--adding-a-new-decoder-format).
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 05 / How It Works
|
|
250
|
+
|
|
251
|
+
### The pipeline
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
input.mp4
|
|
255
|
+
→ ffprobe (identify streams)
|
|
256
|
+
→ auto_detect / --decoder (choose decoder, report confidence %)
|
|
257
|
+
→ decoder.decode(...) (per-format)
|
|
258
|
+
→ KSFDocument (universal in-memory model)
|
|
259
|
+
→ writers (CSV, JSON, GPX, ASS) (format-agnostic)
|
|
260
|
+
→ renderer (Pillow HUD, optional) (format-agnostic)
|
|
261
|
+
→ ffmpeg burn + re-encode (format-agnostic)
|
|
262
|
+
→ input.hud.mp4
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Every decoder produces the same `KSFDocument` (a list of `KSFFrame` objects plus metadata). Every output writer consumes that shape. New formats only touch the decoder.
|
|
266
|
+
|
|
267
|
+
### The Audi A5 decoder (worked example)
|
|
268
|
+
|
|
269
|
+
`ffprobe` on a stock Audi A5 dashcam export reveals an extra track alongside the video and audio:
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
Stream #0:0 Video : hevc (Main 10), 3840×2160, 30 fps
|
|
273
|
+
Stream #0:1 Audio : aac, 48000 Hz, stereo
|
|
274
|
+
Stream #0:2 Subtitle : mov_text (tx3g) ← telemetry channel
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
The subtitle stream is the entire telemetry channel. The in-car player reads it; every external player ignores it.
|
|
278
|
+
|
|
279
|
+
Each cue is a 3GPP timed-text payload of the form:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
{\an7}<font size="0">PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwhRG9j…</font>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
The `<font size="0">` makes the cue invisible if a player ever did try to render it. The base64 blob inside decodes to a binary Protocol Buffers message at roughly 5 Hz.
|
|
286
|
+
|
|
287
|
+
There is no `.proto` file. There does not need to be: the firmware writes **field names as plaintext strings** directly into the wire format alongside their values. A single frame looks roughly like:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
id200_01 "2026-05-04T07:14:24+00:00"
|
|
291
|
+
id200_02 "52.606677242"
|
|
292
|
+
id200_03 "11.849491519"
|
|
293
|
+
id200_05 9.138 (speed, m/s)
|
|
294
|
+
id200_06 774116.0 (odometer, m)
|
|
295
|
+
idOC_02 "Scharnhorststrasse"
|
|
296
|
+
idOC_04 "Stendal"
|
|
297
|
+
idOC_06 "DE"
|
|
298
|
+
idOC_40 "t11_DEU_1p0_2p50_3p0_1s0"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
klartext walks the wire bytes, reads each `(tag, name, value)` triple, and binds the result into a strongly-typed `KSFFrame`. No protobuf library is used — the decoder is ~80 lines.
|
|
302
|
+
|
|
303
|
+
### The HUD renderer
|
|
304
|
+
|
|
305
|
+
When `Pillow` is installed, klartext renders a graphical HUD that mimics the Audi MMI playback overlay:
|
|
306
|
+
|
|
307
|
+
- **top-left** — semi-transparent panel with date/time + `(<country>) <city> – <street>`
|
|
308
|
+
- **bottom-left** — satellite minimap with a heading-aware GPS marker
|
|
309
|
+
- **bottom-centre** — `‹‹ NN km/h ››` speed readout
|
|
310
|
+
- **bottom-right** — small klartext brand watermark
|
|
311
|
+
|
|
312
|
+
The renderer writes each composite as a frame in a transparent overlay video, which is then composited and re-encoded onto the source by ffmpeg.
|
|
313
|
+
|
|
314
|
+
When `Pillow` is not installed, klartext falls back to an ASS subtitle overlay covering the same text content (no minimap, no graphical icons).
|
|
315
|
+
|
|
316
|
+
### The minimap
|
|
317
|
+
|
|
318
|
+
The minimap composites raster tiles behind a GPS marker:
|
|
319
|
+
|
|
320
|
+
- **ESRI World Imagery** — satellite imagery (the default, no token required).
|
|
321
|
+
- **Mapbox satellite-streets** — optional, higher detail at low zooms, requires a free token. klartext tracks your monthly tile usage against Mapbox's 50,000-tile free tier and prints what's left at the end of each run.
|
|
322
|
+
|
|
323
|
+
When the GPS heading is established (after enough samples to derive a stable direction), the marker rotates to point along the track. Before that, it shows a static disc.
|
|
324
|
+
|
|
325
|
+
Tiles are cached to `~/.cache/klartext/tiles/` so repeated processing of nearby clips reuses what's already on disk.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## 06 / Telemetry Field Reference
|
|
330
|
+
|
|
331
|
+
This section documents the **Audi A5 schema** specifically. Other formats will get their own reference sections as their decoders land.
|
|
332
|
+
|
|
333
|
+
The Audi A5 dashcam writes two related blocks per cue. Field names appear stable across the firmware versions we've seen; semantics are not always known.
|
|
334
|
+
|
|
335
|
+
### Primary frame — `id200_*`
|
|
336
|
+
|
|
337
|
+
Per-cue dynamic measurements. **Confirmed** through round-trip verification (e.g., the integral of `id200_05` matches the delta of `id200_06` to within float-rounding).
|
|
338
|
+
|
|
339
|
+
| Field | Type | Meaning | Status |
|
|
340
|
+
|---|---|---|---|
|
|
341
|
+
| `id200_01` | string | UTC timestamp, ISO 8601 | Confirmed |
|
|
342
|
+
| `id200_02` | string | Latitude, decimal degrees, WGS-84 | Confirmed |
|
|
343
|
+
| `id200_03` | string | Longitude, decimal degrees, WGS-84 | Confirmed |
|
|
344
|
+
| `id200_04` | float | GPS carrier-to-noise ratio (C/N₀), dB-Hz | Confirmed |
|
|
345
|
+
| `id200_05` | float | Ground speed, m/s — multiply by 3.6 for km/h | Confirmed |
|
|
346
|
+
| `id200_06` | float | Cumulative odometer, metres | Confirmed |
|
|
347
|
+
|
|
348
|
+
### Context frame — `idOC_*`
|
|
349
|
+
|
|
350
|
+
Static and state fields. Some have plaintext semantic content; many are integer flags whose meaning is not yet known.
|
|
351
|
+
|
|
352
|
+
Status legend: **Confirmed** = decoded and verified; **Hypothesis** = best guess from observed values, needs confirmation; **Unknown** = field name only, no behaviour observed yet.
|
|
353
|
+
|
|
354
|
+
| Field | Type | Meaning / hypothesis | Status |
|
|
355
|
+
|---|---|---|---|
|
|
356
|
+
| `idOC_02` | string | Street name (`---` when off-road / no match) | Confirmed |
|
|
357
|
+
| `idOC_04` | string | City | Confirmed |
|
|
358
|
+
| `idOC_06` | string | ISO 3166-1 alpha-2 country code | Confirmed |
|
|
359
|
+
| `idOC_08` | string | region / sub-city district | Hypothesis |
|
|
360
|
+
| `idOC_09` | int (1) | recording active flag | Hypothesis |
|
|
361
|
+
| `idOC_10` | int (0) | always 0 in observed data | Unknown |
|
|
362
|
+
| `idOC_11` | int (0) | always 0 in observed data | Unknown |
|
|
363
|
+
| `idOC_12` | int (0/1) | right turn indicator — 1 while the right stalk is active | Confirmed |
|
|
364
|
+
| `idOC_13` | int (0/1) | left turn indicator — 1 while the left stalk is active | Confirmed |
|
|
365
|
+
| `idOC_14` | int (0) | always 0 in observed data | Unknown |
|
|
366
|
+
| `idOC_15` | int (0/1) | high-beam headlights active | Confirmed |
|
|
367
|
+
| `idOC_16` | int (0) | always 0 in observed data | Unknown |
|
|
368
|
+
| `idOC_19` | int (0) | always 0 in observed data | Unknown |
|
|
369
|
+
| `idOC_21` | enum | always `NONE` so far — likely a warning category | Hypothesis |
|
|
370
|
+
| `idOC_24` | enum | `WarningZero` / `WarningSeven` observed — likely a warning level | Hypothesis |
|
|
371
|
+
| `idOC_25` | enum | always `TextZero` so far — likely a text-overlay slot | Hypothesis |
|
|
372
|
+
| `idOC_26` | enum | always `RequestZero` so far — likely a request-type slot | Hypothesis |
|
|
373
|
+
| `idOC_27` | enum | always `RequestZero` so far — likely a second request slot | Hypothesis |
|
|
374
|
+
| `idOC_28` | int (0) | always 0 in observed data | Unknown |
|
|
375
|
+
| `idOC_29` | int (0) | always 0 in observed data | Unknown |
|
|
376
|
+
| `idOC_30` | int (0) | always 0 in observed data | Unknown |
|
|
377
|
+
| `idOC_31` | int (0) | always 0 in observed data | Unknown |
|
|
378
|
+
| `idOC_32` | int (0) | always 0 in observed data | Unknown |
|
|
379
|
+
| `idOC_40` | string | head-unit firmware string | Confirmed |
|
|
380
|
+
| `idOC_41` | string | mostly empty; occasionally a second firmware-shaped string — possibly companion-component firmware | Hypothesis |
|
|
381
|
+
| `idOC_42` | string | vehicle model identifier | Hypothesis |
|
|
382
|
+
| `idOC_46` | int (0/1) | warning triangle / hazard indicator — 1 when active | Confirmed |
|
|
383
|
+
|
|
384
|
+
### Derived fields
|
|
385
|
+
|
|
386
|
+
Computed by klartext, not present in the raw stream:
|
|
387
|
+
|
|
388
|
+
| Field | Type | Meaning |
|
|
389
|
+
|---|---|---|
|
|
390
|
+
| `heading` | float | bearing in degrees from north, clockwise, derived from consecutive GPS positions with EMA smoothing |
|
|
391
|
+
| `speed_kmh` | float | convenience conversion of `speed_ms × 3.6` |
|
|
392
|
+
|
|
393
|
+
### Help wanted
|
|
394
|
+
|
|
395
|
+
The fastest way to upgrade an *Unknown* row to a *Hypothesis*, or a *Hypothesis* to *Confirmed*, is to capture footage of a known event and look at which fields move:
|
|
396
|
+
|
|
397
|
+
- a sharp brake → which counter increments?
|
|
398
|
+
- a g-sensor event (speed bump, pothole) → which integer becomes non-zero?
|
|
399
|
+
- crossing a country border → when does `idOC_06` flip?
|
|
400
|
+
- a dashcam firmware update → does `idOC_41` change? does `idOC_42` appear?
|
|
401
|
+
- a lane-assist warning → which enum field changes?
|
|
402
|
+
|
|
403
|
+
If you find a match, please open a PR against this table. The workflow is in [`CONTRIBUTING.md`](./CONTRIBUTING.md#06--reverse-engineering-an-unknown-field).
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 07 / CLI Reference
|
|
408
|
+
|
|
409
|
+
```text
|
|
410
|
+
klartext INPUT.MP4 [options]
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Core
|
|
414
|
+
|
|
415
|
+
| Flag | Default | Description |
|
|
416
|
+
|---|---|---|
|
|
417
|
+
| `INPUT.MP4` | — | the dashcam export to process |
|
|
418
|
+
| `-o, --output-dir DIR` | input dir | destination directory |
|
|
419
|
+
| `--decoder ID` | auto | force a specific decoder by ID; use `list` to show all (`--decoder list`) |
|
|
420
|
+
| `--external-telemetry FILE` | — | external `.gpx` sidecar to fill GPS gaps in the decoded data |
|
|
421
|
+
| `--version` | — | print version and exit |
|
|
422
|
+
| `-v, --verbose` | off | print every detected raw decoder field with its type and first observed value |
|
|
423
|
+
| `--stats-only` | off | decode telemetry, print trip statistics (speed, distance, GPS, countries …), and exit without writing any output files |
|
|
424
|
+
|
|
425
|
+
### Clip controls
|
|
426
|
+
|
|
427
|
+
| Flag | Default | Description |
|
|
428
|
+
|---|---|---|
|
|
429
|
+
| `--preview SECS` | off | process only the first `SECS` seconds of the clip — useful for fast iteration |
|
|
430
|
+
| `--trim START END` | off | process only the `[START, END)` window; times as `[[HH:]MM:]SS[.ff]` or bare seconds (e.g. `30 90` or `0:30 1:30`) |
|
|
431
|
+
| `--speed-unit {kmh,mph}` | `kmh` | speed display unit used in the HUD, ASS subtitle, the HTML map, and `--stats-only` output |
|
|
432
|
+
|
|
433
|
+
### Exports
|
|
434
|
+
|
|
435
|
+
| Flag | Default | Description |
|
|
436
|
+
|---|---|---|
|
|
437
|
+
| `--no-csv` | off | skip writing the CSV telemetry table |
|
|
438
|
+
| `--no-json` | off | skip writing the JSON telemetry file |
|
|
439
|
+
| `--no-gpx` | off | skip writing the GPX track |
|
|
440
|
+
| `--export-ksf` | off | also write `<name>.ksf.json` — the full KSF normalised document (useful for scripting) |
|
|
441
|
+
| `--html-map` | off | write a self-contained Leaflet.js interactive route viewer (`<name>.map.html`) with speed-coloured segments, hover panel, and sidebar statistics; internet connection required only for map tiles |
|
|
442
|
+
| `--chapters` | off | detect chapter events (clip start, stops, country crossings) and write `<name>.chapters.ffmeta`; automatically injected into the re-encoded video |
|
|
443
|
+
| `--thumbnail [TIMESTAMP]` | off | export a HUD-composited JPEG thumbnail (`<name>.thumb.jpg`) at `TIMESTAMP` (`[[HH:]MM:]SS[.ff]` or bare seconds); omit the value to use the video midpoint |
|
|
444
|
+
|
|
445
|
+
### Batch processing
|
|
446
|
+
|
|
447
|
+
| Flag | Default | Description |
|
|
448
|
+
|---|---|---|
|
|
449
|
+
| `--batch DIR` | off | process every MP4 in `DIR` with the same options; the positional `input` argument is ignored; prints a per-file ✓/✗ summary at the end |
|
|
450
|
+
|
|
451
|
+
### Render & encode
|
|
452
|
+
|
|
453
|
+
| Flag | Default | Description |
|
|
454
|
+
|---|---|---|
|
|
455
|
+
| `--no-burn` | off | skip the video re-encode; only export data + `.ass` |
|
|
456
|
+
| `--no-video` | off | skip HUD rendering and video output entirely; only export telemetry, GPX, and ASS |
|
|
457
|
+
| `--stream-copy` | off | embed the ASS subtitle as a soft track via stream-copy — no re-encode, very fast, but the subtitle is not burned in (requires player support for soft subs) |
|
|
458
|
+
| `--encoder NAME` | auto | force a specific ffmpeg encoder (`hevc_nvenc`, `hevc_qsv`, `hevc_vaapi`, `libx265`, `libx264`) |
|
|
459
|
+
| `--crf N` | 22 | quality (CRF / CQ / QP depending on encoder) |
|
|
460
|
+
| `--font NAME` | DejaVu Sans | HUD font family |
|
|
461
|
+
| `--whatsapp` | off | encode for WhatsApp compatibility: forces `libx264`, `yuv420p`, H.264 Main profile level 4.0 |
|
|
462
|
+
| `--strip-telemetry` | off | drop the hidden telemetry track from the output — recommended when sharing |
|
|
463
|
+
|
|
464
|
+
### Minimap
|
|
465
|
+
|
|
466
|
+
| Flag | Default | Description |
|
|
467
|
+
|---|---|---|
|
|
468
|
+
| `--no-map` | off | skip the satellite minimap (use ASS-only HUD, or for offline runs) |
|
|
469
|
+
| `--mapbox` | off | use Mapbox satellite-streets tiles instead of ESRI |
|
|
470
|
+
| `--mapbox-token TOKEN` | — | save a Mapbox token to the config file; can be used standalone without a video file |
|
|
471
|
+
| `--map-zoom N` | 16 | satellite tile zoom level for the minimap |
|
|
472
|
+
| `--map-size PX` | auto | minimap panel size in pixels (default: 25 % of shorter video dimension, min 180) |
|
|
473
|
+
|
|
474
|
+
### Configuration paths
|
|
475
|
+
|
|
476
|
+
| Path | Purpose |
|
|
477
|
+
|---|---|
|
|
478
|
+
| `~/.config/klartext/config.json` | persisted settings (currently: Mapbox token, monthly usage counter) |
|
|
479
|
+
| `~/.cache/klartext/tiles/` | cached satellite & navigation tiles |
|
|
480
|
+
|
|
481
|
+
Environment variables `MAPBOX_TOKEN` or `KLARTEXT_MAPBOX_TOKEN` are honoured as fallbacks if no token is in the config file.
|
|
482
|
+
|
|
483
|
+
### Privacy note on `--strip-telemetry`
|
|
484
|
+
|
|
485
|
+
The hidden telemetry track contains your **GPS coordinates, timestamps, street names, and odometer**. When you share a dashcam clip with anyone — insurance, police, social media — that track travels with the video unless you strip it. `--strip-telemetry` produces a clean output that retains the rendered HUD but discards the underlying raw stream.
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## 08 / Watermark Policy
|
|
490
|
+
|
|
491
|
+
klartext renders a small `klartext` mark in the lower-right corner of the output video. It is intentionally small (≈10 % of frame width), low-contrast, and unobtrusive.
|
|
492
|
+
|
|
493
|
+
It exists for two reasons:
|
|
494
|
+
|
|
495
|
+
1. **Attribution.** When a clip with a klartext-style HUD shows up online, it should be obvious which tool produced it.
|
|
496
|
+
2. **Provenance.** If the underlying telemetry is later disputed, the mark indicates which decoder was used.
|
|
497
|
+
|
|
498
|
+
Contributors are asked not to remove or disable the watermark in pull requests. Refining its size, placement, contrast, opacity, or styling is welcome; deleting it is not. Forks for personal use are free to do as they wish — that is what open-source means. The request applies to contributions back to the canonical repository.
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## 09 / Roadmap
|
|
503
|
+
|
|
504
|
+
Highlights, in roughly the order they're expected to land:
|
|
505
|
+
|
|
506
|
+
**Landed since v1.0.0:** `--preview`, `--trim`, `--speed-unit`, `--html-map`, `--thumbnail`, `--stream-copy`, `--batch`, `--stats-only`, `--chapters`, PyPI publishing (`pip install klartext`)
|
|
507
|
+
|
|
508
|
+
**Up next:**
|
|
509
|
+
|
|
510
|
+
- **format coverage** — decoders for GPMF, DJI SRT, NMEA 0183 sidecars, Novatek embedded
|
|
511
|
+
- additional HUD modules (speed history, altitude, compass, trip distance)
|
|
512
|
+
- a configurable HUD layout with freely movable components
|
|
513
|
+
- a browser-based HUD designer at **klartext.dev**
|
|
514
|
+
- expanded vehicle coverage within existing formats (E3 1.2 siblings)
|
|
515
|
+
|
|
516
|
+
The full plan with status, prioritisation, and open questions lives in [`ROADMAP.md`](./ROADMAP.md).
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## 10 / Contributing
|
|
521
|
+
|
|
522
|
+
klartext is open-source and will stay that way. The shape of the project — *first-class Audi support today, every dashcam tomorrow* — only works through contributions.
|
|
523
|
+
|
|
524
|
+
Where you can help:
|
|
525
|
+
|
|
526
|
+
- **bug reports & fixes** — open an issue or a PR
|
|
527
|
+
- **security findings** — see the dedicated section in `CONTRIBUTING.md`
|
|
528
|
+
- **a new decoder format** — share a clip from a dashcam klartext can't read yet, plus everything you can find about it; the maintainers handle the decoder code (writing it yourself is welcome too, but optional)
|
|
529
|
+
- **a new vehicle inside an existing format** — confirm support by sharing a sample clip from your car
|
|
530
|
+
- **reverse-engineering** — help fill in the Unknown / Hypothesis rows in the Field Reference
|
|
531
|
+
- **features** — pick a roadmap item or propose your own
|
|
532
|
+
- **documentation** — typo fixes, translations, clearer phrasing
|
|
533
|
+
|
|
534
|
+
The full process, code style, decoder interface, and the new-vehicle workflow live in [`CONTRIBUTING.md`](./CONTRIBUTING.md).
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## 11 / License
|
|
539
|
+
|
|
540
|
+
[MIT](./LICENSE) for the source code.
|
|
541
|
+
Brand assets in `assets/` are © the klartext authors — all rights reserved unless otherwise noted.
|
|
542
|
+
The embedded glyph outlines in the brand SVGs derive from DejaVu Sans Bold (OFL-1.1).
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## 12 / Acknowledgements
|
|
547
|
+
|
|
548
|
+
- the FFmpeg project, without which none of this exists
|
|
549
|
+
- the GoPro GPMF authors for publishing the gpmd specification
|
|
550
|
+
- the DejaVu Sans contributors for an OFL grotesque that survived being chopped into a logo
|
|
551
|
+
- ESRI for the open World Imagery tile service, and Mapbox for a usable free tier
|
|
552
|
+
- everyone who has ever filed an issue with a hex dump attached
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
<p align="center">
|
|
557
|
+
<picture>
|
|
558
|
+
<source media="(prefers-color-scheme: dark)" srcset="brand/klartext-icon-dark.svg">
|
|
559
|
+
<img src="brand/klartext-icon.svg" alt="" width="48">
|
|
560
|
+
</picture>
|
|
561
|
+
</p>
|
|
562
|
+
|
|
563
|
+
<p align="center">
|
|
564
|
+
<code>klartext.dev</code>
|
|
565
|
+
</p>
|