Skip to content

Commit ed281e3

Browse files
committed
Release v0.1.5
1 parent 93b096c commit ed281e3

File tree

19 files changed

+588
-58
lines changed

19 files changed

+588
-58
lines changed

Cargo.lock

Lines changed: 52 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "telemetry-parser"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
authors = ["Adrian <[email protected]>"]
55
edition = "2018"
66
license = "MPL-2.0"
@@ -18,6 +18,8 @@ serde = { version = "1", features = ["derive"] }
1818
serde_json = { version = "1", features = ["preserve_order"] }
1919
argh = "0.1"
2020
memchr = "2.4"
21+
fc-blackbox = { version = "*", git = "https://github.com/AdrianEddy/fc-blackbox.git" }
22+
csv = "1.1"
2123

2224
quick-xml = { version = "0.22", optional = true }
2325

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Work in progress, the code is already working but I plan to add much more input
77
- [x] Sony (RX0 II, a7s III, RX100 VII, ZV1, a7c, a7r IV, a6600, a9 II, a1, FX3, ZV-E10, FX6)
88
- [x] GoPro (All models with gyro metadata, starting with HERO 5)
99
- [x] Insta360 (OneR, SMO 4k, GO2)
10-
- [ ] TODO Betaflight blackbox (CSV and Binary)
11-
- [ ] TODO Runcam CSV
10+
- [x] Betaflight blackbox (CSV and Binary)
11+
- [x] Runcam CSV (Runcam 5 Orange, iFlight GOCam GR)
1212
- [ ] TODO DJI flight logs (*.dat, *.txt)
1313

1414
# Example usage
@@ -21,6 +21,12 @@ Dump all metadata found in the source file.
2121
gyro2bb --dump file.mp4
2222
```
2323

24+
25+
# Python module
26+
Python module is available on [PyPI](https://pypi.org/project/telemetry-parser/).
27+
Details in [bin/python-module](https://github.com/AdrianEddy/telemetry-parser/tree/master/bin/python-module)
28+
29+
2430
# Building
2531
1. Get latest stable Rust language from: https://rustup.rs/
2632
2. Clone the repo: `git clone https://github.com/AdrianEddy/telemetry-parser.git`

bin/gyro2bb/Cargo.lock

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/gyro2bb/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gyro2bb"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
authors = ["Adrian <[email protected]>"]
55
edition = "2018"
66

bin/gyro2bb/gyro2bb.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use argh::FromArgs;
44
use telemetry_parser::*;
55
use telemetry_parser::tags_impl::*;
66

7-
/** gyro2bb v0.1.4
7+
/** gyro2bb v0.1.5
88
Author: Adrian <[email protected]>
99
1010
Extract gyro data from Sony, GoPro and Insta360 cameras to betaflight blackbox csv log
@@ -31,7 +31,9 @@ fn main() {
3131
let mut stream = std::fs::File::open(&opts.input).unwrap();
3232
let filesize = stream.metadata().unwrap().len() as usize;
3333

34-
let input = Input::from_stream(&mut stream, filesize).unwrap();
34+
let filename = std::path::Path::new(&opts.input).file_name().unwrap().to_str().unwrap();
35+
36+
let input = Input::from_stream(&mut stream, filesize, filename).unwrap();
3537

3638
let mut i = 0;
3739
println!("Detected camera: {} {}", input.camera_type(), input.camera_model().unwrap_or(&"".into()));
@@ -54,6 +56,8 @@ fn main() {
5456
let imu_data = util::normalized_imu(&input, opts.imuo).unwrap();
5557

5658
let mut csv = String::with_capacity(2*1024*1024);
59+
csv.push_str(r#""Product","Blackbox flight data recorder by Nicholas Sherlock""#);
60+
csv.push('\n');
5761
crate::try_block!({
5862
let map = samples[0].tag_map.as_ref()?;
5963
let json = (map.get(&GroupId::Default)?.get_t(TagId::Metadata) as Option<&serde_json::Value>)?;

bin/python-module/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "telemetry-parser-py"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
authors = ["Adrian <[email protected]>"]
55
edition = "2018"
66

bin/python-module/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# telemetry-parser-py
2-
`telemetry-parser` python module
32
Library to parse real-time metadata embedded in video files or telemetry from other sources.
43

54
Work in progress, the code is already working but I plan to add much more input and output formats.
@@ -8,8 +7,8 @@ Work in progress, the code is already working but I plan to add much more input
87
- [x] Sony (RX0 II, a7s III, RX100 VII, ZV1, a7c, a7r IV, a6600, a9 II, a1, FX3, ZV-E10, FX6)
98
- [x] GoPro (All models with gyro metadata, starting with HERO 5)
109
- [x] Insta360 (OneR, SMO 4k, GO2)
11-
- [ ] TODO Betaflight blackbox (CSV and Binary)
12-
- [ ] TODO Runcam CSV
10+
- [x] Betaflight blackbox (CSV and Binary)
11+
- [x] Runcam CSV (Runcam 5 Orange, iFlight GOCam GR)
1312
- [ ] TODO DJI flight logs (*.dat, *.txt)
1413

1514
# Example usage:

bin/python-module/python-module.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ impl Parser {
2020
let mut stream = std::fs::File::open(&path)?;
2121
let filesize = stream.metadata()?.len() as usize;
2222

23-
let input = Input::from_stream(&mut stream, filesize)?;
23+
let filename = std::path::Path::new(&path).file_name().unwrap_or_default().to_str().unwrap_or_default();
24+
25+
let input = Input::from_stream(&mut stream, filesize, filename)?;
2426

2527
Ok(Self {
2628
camera: Some(input.camera_type()),
@@ -42,7 +44,7 @@ impl Parser {
4244
let groups_map = info.tag_map.as_ref().unwrap();
4345

4446
for (group, map) in groups_map {
45-
let group_map = groups.entry(group).or_insert(BTreeMap::new());
47+
let group_map = groups.entry(group).or_insert_with(BTreeMap::new);
4648
for (tagid, info) in map {
4749
let value = if human_readable.unwrap_or(false) {
4850
serde_json::to_value(info.value.to_string())

src/blackbox/binary.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::rc::*;
2+
use std::io::*;
3+
4+
use crate::tags_impl::*;
5+
use crate::*;
6+
use memchr::memmem;
7+
use fc_blackbox::BlackboxRecord;
8+
9+
pub fn parse<T: Read + Seek>(stream: &mut T, _size: usize) -> Result<Vec<SampleInfo>> {
10+
let mut samples = Vec::new();
11+
let mut bytes = Vec::new();
12+
stream.read_to_end(&mut bytes)?;
13+
14+
for index in memmem::find_iter(&bytes, b"H Product:Blackbox") {
15+
if let Some(end) = memmem::find(&bytes[index..], b"End of log\0") {
16+
let log = &bytes[index..index+end+11];
17+
18+
let mut bbox = fc_blackbox::BlackboxReader::from_bytes(log).unwrap();
19+
20+
// Remove acc_1G from `other_headers` because we will have it in Accelerometer/Scale tag, instead of in metadata
21+
let accl_scale = bbox.header.other_headers.remove("acc_1G").unwrap_or("1.0".to_owned()).parse::<f64>().unwrap();
22+
let gyro_scale = bbox.header.org_gyro_scale as f64;
23+
24+
let mut map = GroupedTagMap::new();
25+
26+
util::insert_tag(&mut map, tag!(parsed GroupId::Default, TagId::Metadata, "Extra metadata", Json, |v| format!("{:?}", v), {
27+
serde_json::to_value(&bbox.header.other_headers).map_err(|_| Error::new(ErrorKind::Other, "Serialize error"))?
28+
}, vec![]));
29+
util::insert_tag(&mut map, tag!(parsed GroupId::Gyroscope, TagId::Scale, "Gyroscope scale", f64, |v| format!("{:?}", v), gyro_scale, vec![]));
30+
util::insert_tag(&mut map, tag!(parsed GroupId::Accelerometer, TagId::Scale, "Accelerometer scale", f64, |v| format!("{:?}", v), accl_scale, vec![]));
31+
32+
let headers = bbox.header.ip_fields_in_order.iter().map(|x| x.name.as_str()).collect::<Vec<&str>>();
33+
let mut column_struct = super::BlackBox::prepare_vectors_from_headers(&headers);
34+
35+
while let Some(record) = bbox.next() {
36+
match record {
37+
BlackboxRecord::Main(values) => {
38+
let time = values[1] as f64 / 1_000_000.0;
39+
for (col, &value) in column_struct.columns.iter().zip(values) {
40+
let mut desc = col.desc.as_ref().borrow_mut();
41+
super::BlackBox::insert_value_to_vec(&mut desc, time, value as f64, col.index);
42+
}
43+
}
44+
BlackboxRecord::GNSS(_values) => {
45+
// time,GPS_numSat,GPS_coord[0],GPS_coord[1],GPS_altitude,GPS_speed,GPS_ground_course
46+
// TODO
47+
}
48+
BlackboxRecord::Slow(_values) => {
49+
// TODO
50+
}
51+
BlackboxRecord::Event(_event) => {
52+
// TODO
53+
}
54+
BlackboxRecord::Garbage(_length) => {
55+
// TODO
56+
}
57+
}
58+
}
59+
drop(column_struct.columns); // Release all weak pointers
60+
61+
// Add filled vectors to the tag map
62+
for desc in column_struct.descriptions.drain(..) {
63+
let desc = Rc::try_unwrap(desc).unwrap().into_inner();
64+
util::insert_tag(&mut map, desc);
65+
}
66+
67+
samples.push(SampleInfo { index: 0, timestamp_ms: 0.0, duration_ms: 0.0, tag_map: Some(map) });
68+
}
69+
}
70+
71+
Ok(samples)
72+
}

0 commit comments

Comments
 (0)