pymisb 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.
- pymisb-1.0.0/LICENSE +26 -0
- pymisb-1.0.0/MANIFEST.in +18 -0
- pymisb-1.0.0/PKG-INFO +384 -0
- pymisb-1.0.0/README.md +333 -0
- pymisb-1.0.0/pymisb/__init__.py +13 -0
- pymisb-1.0.0/pymisb/common/__init__.py +15 -0
- pymisb-1.0.0/pymisb/common/dji.py +432 -0
- pymisb-1.0.0/pymisb/common/encoder.py +158 -0
- pymisb-1.0.0/pymisb/common/ts.py +39 -0
- pymisb-1.0.0/pymisb/constants.py +40 -0
- pymisb-1.0.0/pymisb/demux/__init__.py +7 -0
- pymisb-1.0.0/pymisb/demux/__main__.py +3 -0
- pymisb-1.0.0/pymisb/demux/engine.py +206 -0
- pymisb-1.0.0/pymisb/klvdata/__init__.py +13 -0
- pymisb-1.0.0/pymisb/klvdata/common.py +137 -0
- pymisb-1.0.0/pymisb/klvdata/element.py +53 -0
- pymisb-1.0.0/pymisb/klvdata/elementparser.py +146 -0
- pymisb-1.0.0/pymisb/klvdata/klvparser.py +64 -0
- pymisb-1.0.0/pymisb/klvdata/misb0102.py +36 -0
- pymisb-1.0.0/pymisb/klvdata/misb0601.py +674 -0
- pymisb-1.0.0/pymisb/klvdata/misb0903.py +182 -0
- pymisb-1.0.0/pymisb/klvdata/misbEG0104.py +23 -0
- pymisb-1.0.0/pymisb/klvdata/setparser.py +128 -0
- pymisb-1.0.0/pymisb/klvdata/streamparser.py +53 -0
- pymisb-1.0.0/pymisb/mux/__init__.py +7 -0
- pymisb-1.0.0/pymisb/mux/__main__.py +3 -0
- pymisb-1.0.0/pymisb/mux/engine.py +425 -0
- pymisb-1.0.0/pymisb/stream/__init__.py +7 -0
- pymisb-1.0.0/pymisb/stream/__main__.py +3 -0
- pymisb-1.0.0/pymisb/stream/engine.py +264 -0
- pymisb-1.0.0/pymisb/vmti/__init__.py +7 -0
- pymisb-1.0.0/pymisb/vmti/__main__.py +3 -0
- pymisb-1.0.0/pymisb/vmti/engine.py +173 -0
- pymisb-1.0.0/pymisb.egg-info/SOURCES.txt +33 -0
- pymisb-1.0.0/pyproject.toml +45 -0
- pymisb-1.0.0/setup.cfg +4 -0
pymisb-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
License Agreement (pymisb)
|
|
2
|
+
================================
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 Fran Raga. All rights reserved.
|
|
5
|
+
|
|
6
|
+
This software is free and may be used, copied, modified, and distributed
|
|
7
|
+
for any purpose, commercial or non-commercial, without restriction,
|
|
8
|
+
provided that the following conditions are met:
|
|
9
|
+
|
|
10
|
+
1. ATTRIBUTION: Any project, product, publication, or derivative work that
|
|
11
|
+
uses this software (in whole or in part) must include a clear credit to
|
|
12
|
+
the original author:
|
|
13
|
+
|
|
14
|
+
Fran Raga - pymisb
|
|
15
|
+
https://github.com/All4Gis/pymisb
|
|
16
|
+
|
|
17
|
+
This credit must appear in the source code, documentation, README,
|
|
18
|
+
About page, or any other reasonable location visible to end users.
|
|
19
|
+
|
|
20
|
+
2. NO WARRANTY: This software is provided "as is", without warranty of any
|
|
21
|
+
kind, express or implied, including but not limited to the warranties of
|
|
22
|
+
merchantability, fitness for a particular purpose, and noninfringement.
|
|
23
|
+
In no event shall the author be liable for any claim, damages, or other
|
|
24
|
+
liability arising from the use of this software.
|
|
25
|
+
|
|
26
|
+
By using this software you agree to these terms.
|
pymisb-1.0.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
|
|
4
|
+
recursive-include pymisb *.py
|
|
5
|
+
|
|
6
|
+
prune tests
|
|
7
|
+
prune pymisb.egg-info
|
|
8
|
+
prune dist
|
|
9
|
+
prune build
|
|
10
|
+
prune output
|
|
11
|
+
prune sample
|
|
12
|
+
prune assets
|
|
13
|
+
|
|
14
|
+
global-exclude __pycache__
|
|
15
|
+
global-exclude *.pyc
|
|
16
|
+
global-exclude .DS_Store
|
|
17
|
+
global-exclude setup.cfg
|
|
18
|
+
global-exclude *.egg-info
|
pymisb-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pymisb
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: MISB ST0601 / STANAG 4609 mux, demux & live streaming library for Python
|
|
5
|
+
Author-email: Fran Raga <franka1986@gmail.com>
|
|
6
|
+
License: License Agreement (pymisb)
|
|
7
|
+
================================
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 Fran Raga. All rights reserved.
|
|
10
|
+
|
|
11
|
+
This software is free and may be used, copied, modified, and distributed
|
|
12
|
+
for any purpose, commercial or non-commercial, without restriction,
|
|
13
|
+
provided that the following conditions are met:
|
|
14
|
+
|
|
15
|
+
1. ATTRIBUTION: Any project, product, publication, or derivative work that
|
|
16
|
+
uses this software (in whole or in part) must include a clear credit to
|
|
17
|
+
the original author:
|
|
18
|
+
|
|
19
|
+
Fran Raga - pymisb
|
|
20
|
+
https://github.com/All4Gis/pymisb
|
|
21
|
+
|
|
22
|
+
This credit must appear in the source code, documentation, README,
|
|
23
|
+
About page, or any other reasonable location visible to end users.
|
|
24
|
+
|
|
25
|
+
2. NO WARRANTY: This software is provided "as is", without warranty of any
|
|
26
|
+
kind, express or implied, including but not limited to the warranties of
|
|
27
|
+
merchantability, fitness for a particular purpose, and noninfringement.
|
|
28
|
+
In no event shall the author be liable for any claim, damages, or other
|
|
29
|
+
liability arising from the use of this software.
|
|
30
|
+
|
|
31
|
+
By using this software you agree to these terms.
|
|
32
|
+
|
|
33
|
+
Project-URL: Homepage, https://github.com/All4Gis/pymisb
|
|
34
|
+
Project-URL: Repository, https://github.com/All4Gis/pymisb
|
|
35
|
+
Project-URL: Issues, https://github.com/All4Gis/pymisb/issues
|
|
36
|
+
Keywords: dji,misb,stanag,klv,st0601,st0903,vmti,drone,telemetry,gis,streaming
|
|
37
|
+
Classifier: Development Status :: 4 - Beta
|
|
38
|
+
Classifier: Intended Audience :: Developers
|
|
39
|
+
Classifier: Intended Audience :: Science/Research
|
|
40
|
+
Classifier: Topic :: Multimedia :: Video
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
42
|
+
Classifier: Programming Language :: Python :: 3
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
45
|
+
Requires-Python: >=3.12
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
License-File: LICENSE
|
|
48
|
+
Provides-Extra: test
|
|
49
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
50
|
+
Dynamic: license-file
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<img src="assets/banner.png" alt="pymisb — MISB ST0601 / STANAG 4609 mux, demux & streaming" style="width: 100%; height: auto; max-height: 300px; object-fit: contain;">
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
# pymisb
|
|
57
|
+
|
|
58
|
+
[](https://github.com/All4Gis/pymisb/actions/workflows/ci.yml)
|
|
59
|
+
[](https://pypi.org/project/pymisb/)
|
|
60
|
+
|
|
61
|
+
**MISB ST0601 / STANAG 4609** mux, demux & live streaming library for Python.
|
|
62
|
+
|
|
63
|
+
| Module | What it does |
|
|
64
|
+
|--------|-------------|
|
|
65
|
+
| **mux** | Turn DJI drone footage + telemetry into STANAG 4609 videos with embedded KLV |
|
|
66
|
+
| **demux** | Extract and decode KLV telemetry from any STANAG-compliant video file |
|
|
67
|
+
| **stream** | Read KLV in real-time from live UDP/RTP/RTSP streams |
|
|
68
|
+
| **vmti** | Parse MISB ST 0903 VMTI target tracking metadata |
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install pymisb
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> **Donations** — If this project is useful for you, consider buying me a beer! [](https://www.paypal.com/donate/?hosted_button_id=YMHU4Z52S2G8N)
|
|
75
|
+
|
|
76
|
+
## Quick start
|
|
77
|
+
|
|
78
|
+
### Mux — create a MISB video
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from pymisb.common import build_klv_packets
|
|
82
|
+
from pymisb.mux import mux_with_ffmpeg
|
|
83
|
+
|
|
84
|
+
packets = build_klv_packets("telemetry.csv")
|
|
85
|
+
mux_with_ffmpeg("drone.mp4", packets, "output.ts")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Demux — read KLV from a video
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from pymisb.demux import extract_klv, decode_packets
|
|
92
|
+
|
|
93
|
+
klv_data = extract_klv("output.ts")
|
|
94
|
+
packets = decode_packets(klv_data)
|
|
95
|
+
for pkt in packets:
|
|
96
|
+
meta = pkt.MetadataList()
|
|
97
|
+
print(meta[13]) # Sensor Latitude
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Stream — real-time KLV from live feeds
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from pymisb.stream import open_stream
|
|
104
|
+
|
|
105
|
+
with open_stream("udp://@:5000") as reader:
|
|
106
|
+
for pkt in reader:
|
|
107
|
+
meta = pkt.MetadataList()
|
|
108
|
+
print(meta[13]) # Sensor Latitude in real-time
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### VMTI — target tracking metadata
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from pymisb.vmti import parse_vmti, extract_vmti
|
|
115
|
+
|
|
116
|
+
targets = parse_vmti(extract_vmti("video.ts"))
|
|
117
|
+
for t in targets:
|
|
118
|
+
print(t["target_centroid_lat"], t["target_classification"])
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Package structure
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
pymisb/
|
|
125
|
+
├── constants.py Shared constants (keys, versions, FOV, etc.)
|
|
126
|
+
├── common/
|
|
127
|
+
│ ├── encoder.py MISB ST0601 KLV packet builder
|
|
128
|
+
│ ├── dji.py DJI CSV + binary .txt flight record parsers
|
|
129
|
+
│ └── ts.py Path defaults and KLV stream writer
|
|
130
|
+
├── mux/
|
|
131
|
+
│ └── engine.py MPEG-TS muxing (PES/PCR/KLV injection + FFmpeg)
|
|
132
|
+
├── demux/
|
|
133
|
+
│ └── engine.py KLV extraction and decoding from files
|
|
134
|
+
├── stream/
|
|
135
|
+
│ └── engine.py Real-time KLV from UDP/RTP/RTSP streams
|
|
136
|
+
├── vmti/
|
|
137
|
+
│ └── engine.py MISB ST 0903 VMTI target metadata
|
|
138
|
+
└── klvdata/ Vendored MISB ST0601/0903 KLV decoder
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Requirements
|
|
142
|
+
|
|
143
|
+
- **Python 3.12+** (3.12, 3.13)
|
|
144
|
+
- **FFmpeg** on the PATH (for muxing, demuxing, and streaming)
|
|
145
|
+
|
|
146
|
+
## Installation
|
|
147
|
+
|
|
148
|
+
### From PyPI
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pip install pymisb
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### From source
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
git clone https://github.com/All4Gis/pymisb.git
|
|
158
|
+
cd pymisb
|
|
159
|
+
pip install .
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Development (editable)
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
git clone https://github.com/All4Gis/pymisb.git
|
|
166
|
+
cd pymisb
|
|
167
|
+
pip install -e ".[test]"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Verify
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
python -c "from pymisb.constants import UAS_LS_KEY; print('OK')"
|
|
174
|
+
pymisb-mux --help
|
|
175
|
+
pymisb-demux --help
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## CLI usage
|
|
179
|
+
|
|
180
|
+
### Muxing
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# From DJI CSV telemetry
|
|
184
|
+
pymisb-mux --video drone.mp4 --csv telemetry.csv
|
|
185
|
+
pymisb-mux --video drone.mp4 --csv telemetry.csv --out output.ts
|
|
186
|
+
|
|
187
|
+
# From DJI binary .txt flight record
|
|
188
|
+
pymisb-mux --video drone.mp4 --dji-txt DJIFlightRecord.txt
|
|
189
|
+
|
|
190
|
+
# KLV only (no video muxing)
|
|
191
|
+
pymisb-mux --csv telemetry.csv --out output.ts --klv-only
|
|
192
|
+
|
|
193
|
+
# Or via module
|
|
194
|
+
python -m pymisb.mux --video drone.mp4 --csv telemetry.csv
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Demuxing
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Dump all KLV packets
|
|
201
|
+
pymisb-demux output.ts
|
|
202
|
+
|
|
203
|
+
# Playback at the video's real rate
|
|
204
|
+
pymisb-demux output.ts --play
|
|
205
|
+
|
|
206
|
+
# Accelerated playback x4
|
|
207
|
+
pymisb-demux output.ts --play --speed 4
|
|
208
|
+
|
|
209
|
+
# Show every ST0601 tag
|
|
210
|
+
pymisb-demux output.ts --all
|
|
211
|
+
|
|
212
|
+
# Tag tree of the first packet
|
|
213
|
+
pymisb-demux output.ts --structure
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Streaming (live)
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Read KLV from a live UDP stream
|
|
220
|
+
pymisb-stream udp://@:5000
|
|
221
|
+
|
|
222
|
+
# RTSP camera
|
|
223
|
+
pymisb-stream rtsp://camera.local/stream --all
|
|
224
|
+
|
|
225
|
+
# Or via module
|
|
226
|
+
python -m pymisb.stream udp://@:5000
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### VMTI (target tracking)
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Decode VMTI targets from a video
|
|
233
|
+
pymisb-vmti video.ts
|
|
234
|
+
|
|
235
|
+
# Show all target fields
|
|
236
|
+
pymisb-vmti video.ts --all
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Library API
|
|
240
|
+
|
|
241
|
+
### `pymisb.common` — encoder and parsers
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
from pymisb.common import (
|
|
245
|
+
build_st0601_packet, # Build a single ST0601 KLV packet
|
|
246
|
+
build_klv_packets, # Parse DJI CSV -> list of KLV packets
|
|
247
|
+
build_klv_packets_from_txt, # Parse DJI .txt -> list of KLV packets
|
|
248
|
+
default_output, # Generate default output path
|
|
249
|
+
write_klv_stream, # Write packets as raw KLV file
|
|
250
|
+
)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### `pymisb.mux` — MPEG-TS muxing
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
from pymisb.mux import (
|
|
257
|
+
mux_with_ffmpeg, # Full mux pipeline (FFmpeg + KLV injection)
|
|
258
|
+
inject_klv_into_ts, # Low-level: inject KLV into existing TS
|
|
259
|
+
)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `pymisb.demux` — KLV extraction and decoding from files
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
from pymisb.demux import (
|
|
266
|
+
extract_klv, # Extract raw KLV bytes from TS via FFmpeg
|
|
267
|
+
decode_packets, # Decode raw KLV into parsed ST0601 packets
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### `pymisb.stream` — real-time KLV from live streams
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from pymisb.stream import open_stream
|
|
275
|
+
|
|
276
|
+
# Iterator mode — yields packets as they arrive
|
|
277
|
+
with open_stream("udp://@:5000") as reader:
|
|
278
|
+
for pkt in reader:
|
|
279
|
+
meta = pkt.MetadataList()
|
|
280
|
+
print(meta[13])
|
|
281
|
+
|
|
282
|
+
# Callback mode
|
|
283
|
+
def on_packet(pkt):
|
|
284
|
+
print(pkt.MetadataList()[13])
|
|
285
|
+
|
|
286
|
+
reader = open_stream("rtsp://camera.local/stream")
|
|
287
|
+
reader.start(callback=on_packet)
|
|
288
|
+
reader.stop()
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### `pymisb.vmti` — MISB ST 0903 VMTI target tracking
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
from pymisb.vmti import parse_vmti, extract_vmti, decode_vmti_stream
|
|
295
|
+
|
|
296
|
+
# From a TS file
|
|
297
|
+
targets = parse_vmti(extract_vmti("video.ts"))
|
|
298
|
+
for t in targets:
|
|
299
|
+
print(t["target_centroid_lat"], t["target_classification"])
|
|
300
|
+
|
|
301
|
+
# From raw bytes
|
|
302
|
+
targets = decode_vmti_stream(vmti_bytes)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### `pymisb.constants` — shared configuration
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
from pymisb.constants import (
|
|
309
|
+
UAS_LS_KEY, # 16-byte UAS Datalink Local Set universal key
|
|
310
|
+
KLV_HEADER_KEY, # Shifted key for DJI non-standard headers
|
|
311
|
+
ST0601_VERSION, # MISB ST0601 version (Tag 65)
|
|
312
|
+
HFOV_DEG, VFOV_DEG, # Camera field of view (degrees)
|
|
313
|
+
EARTH_MEAN_RADIUS, # WGS-84 radius in meters
|
|
314
|
+
)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Configuration
|
|
318
|
+
|
|
319
|
+
Edit `pymisb/constants.py` to adjust:
|
|
320
|
+
|
|
321
|
+
- `HFOV_DEG` / `VFOV_DEG` — camera field of view (affects sensor footprint)
|
|
322
|
+
- `ST0601_VERSION` — advertised Local Set version (Tag 65)
|
|
323
|
+
|
|
324
|
+
## Supported standards
|
|
325
|
+
|
|
326
|
+
| Standard | Name | Status |
|
|
327
|
+
|----------|------|--------|
|
|
328
|
+
| MISB ST 0601 | UAS Datalink Local Set | Full (encode + decode) |
|
|
329
|
+
| MISB ST 0903 | VMTI (Video Moving Target Indicator) | Decode |
|
|
330
|
+
| MISB ST 0102 | Security Metadata | Decode (via klvdata) |
|
|
331
|
+
| MISB EG 0104 | UAV Basic Universal Metadata | Decode (via klvdata) |
|
|
332
|
+
| STANAG 4609 | NATO video standard | Full (mux + demux) |
|
|
333
|
+
|
|
334
|
+
## Testing
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
# Install with test dependencies
|
|
338
|
+
pip install -e ".[test]"
|
|
339
|
+
|
|
340
|
+
# Run all tests
|
|
341
|
+
pytest tests/ -v
|
|
342
|
+
|
|
343
|
+
# Run specific test file
|
|
344
|
+
pytest tests/test_misb_common.py -v
|
|
345
|
+
|
|
346
|
+
# Run specific test
|
|
347
|
+
pytest tests/test_misb_common.py::TestBuildSt0601Packet -v
|
|
348
|
+
|
|
349
|
+
# With coverage
|
|
350
|
+
pip install pytest-cov
|
|
351
|
+
pytest tests/ --cov=pymisb --cov-report=term-missing
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
| Test file | Coverage |
|
|
355
|
+
|-----------|----------|
|
|
356
|
+
| `tests/test_misb_common.py` | ST0601 encoder, DJI parsers, BER/BCC, geometry |
|
|
357
|
+
| `tests/test_misb_mux.py` | MPEG-TS primitives (PES, PTS, PCR, packetization) |
|
|
358
|
+
| `tests/test_klvdata.py` | Vendored klvdata decoder (ST0601 tags, BER-TLV, integration) |
|
|
359
|
+
|
|
360
|
+
CI runs on every push across Python 3.12-3.13 on Linux, macOS, and Windows.
|
|
361
|
+
|
|
362
|
+
## Publishing
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# Build
|
|
366
|
+
pip install build
|
|
367
|
+
python -m build
|
|
368
|
+
|
|
369
|
+
# Publish to PyPI
|
|
370
|
+
pip install twine
|
|
371
|
+
twine upload dist/*
|
|
372
|
+
|
|
373
|
+
# Or TestPyPI first
|
|
374
|
+
twine upload --repository testpypi dist/*
|
|
375
|
+
pip install --index-url https://test.pypi.org/simple/ pymisb
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
> _"From raw drone footage to geospatial intelligence — one KLV packet at a time."_
|
|
381
|
+
|
|
382
|
+
Made with passion by **Fran Raga** <franka1986@gmail.com> - June 2026.
|
|
383
|
+
|
|
384
|
+
If this saved you a few hours, give the repo a star and fly safe. Happy coding!
|