Skip to content

Commit

Permalink
v0.3.1 Various internal changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jenslar committed Jul 22, 2023
1 parent 24c24ac commit 4ed45d4
Show file tree
Hide file tree
Showing 28 changed files with 442 additions and 634 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# 2023-03-23, v0.2.0
# 2023-07-19 0.3.1
- Internal changes

# 2023-03-23 0.2.0
- Fixed export of coordinates for `GPS9` devices (Hero11 and later)
14 changes: 9 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
[package]
name = "gpmf-rs"
version = "0.3.0"
version = "0.3.1"
edition = "2021"
description = "Extract, parse GoPro GPMF data."
repository = "https://github.com/jenslar/gpmf-rs"
license = "MIT"
keywords = ["gopro", "gpmf", "telemetry", "gps", "sensors", "action camera"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
binread = "2.2"
rayon = "1.5.3"
time = {version = "0.3", features = ["formatting", "parsing", "macros"]}
rayon = "1.7.0"
time = {version = "0.3.23", features = ["formatting", "parsing", "macros"]}
walkdir = "2.3.2"
geojson = {version = "0.24", features = ["geo-types"]}
mp4iter = {git = "https://github.com/jenslar/mp4iter.git"}
jpegiter = {git = "https://github.com/jenslar/jpegiter.git"}
blake3 = "1.3.3"
blake3 = "1.4.1"
binrw = "0.11.2"
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,24 @@ gpmf-rs = {git = "https://github.com/jenslar/gpmf-rs.git"}

`src/main.rs`:
```rs
use gpmf_rs::Gpmf;
use gpmf_rs::{Gpmf, SensorType};
use std::path::Path;

fn main() -> std::io::Result<()> {
let path = Path::new("GOPRO_VIDEO.MP4");
let gpmf = Gpmf::new(&path)?;

// Extract GPMF data without printing debug info while parsing
let gpmf = Gpmf::new(&path, false)?;
println!("{gpmf:#?}");

// Filter and process GPS log, prune points that do not have at least a 2D fix
let gps = gpmf.gps().prune(2);
println!("{gps:#?}");

// Filter and process accelerometer data.
let sensor = gpmf.sensor(&SensorType::Accelerometer);
println!("{sensor:#?}");

Ok(())
}
```
98 changes: 68 additions & 30 deletions src/content_types/data_types.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,77 @@
/// Stream type, mostly for internal use.
/// This will have to be updated if new stream types are added or STNM free text descriptions change.
//! GPMF data type. These may change as new models are released,
//! and not all types are available in all cameras.

/// GPMF data type.
/// This will have to be updated if new data types are added or
/// future devices change the description given by the `STNM` stream.
///
/// Model names may be missing and will be updated with new sample data.
/// Only models that are confirmed for each data type are listed.
#[derive(Debug, Clone)]
pub enum DataType {
/// Accelerometer
Accelerometer, // Hero 7, 9
/// Accelerometer (up/down, right/left, forward/back)
AccelerometerUrf, // Hero 5, 6
AgcAudioLevel, // Hero 9
AverageLuminance, // Hero 7
CameraOrientation, // Hero 9
ExposureTime, // Hero 7, 9
FaceCoordinates, // Hero 7, 9
Gps5, // Hero 5, 6, 7, 9, 10, 11
Gps9, // Hero 11
GravityVector, // Hero 9
Gyroscope, // Hero 7, 9
GyroscopeZxy, // Hero 5, 6
ImageUniformity, // Hero 7, 9
ImageOrientation, // Hero 9
LrvFrameSkip, // Hero 9
MicrophoneWet, // Hero 9
MrvFrameSkip, // Hero 9
PredominantHue, // Hero 7
SceneClassification, // Hero 7
SensorGain, // Fusion
SensorIso, // Hero 7, 9
SensorReadOutTime, // Hero 7
WhiteBalanceRgbGains, // Hero 7, 9
WhiteBalanceTemperature, // Hero 7, 9
WindProcessing, // Hero 9
/// `Accelerometer`.
/// Present for Hero 7, 9.
Accelerometer,
/// `Accelerometer (up/down, right/left, forward/back)`.
/// Present for Hero 5, 6.
AccelerometerUrf,
/// Present for Hero 9.
AgcAudioLevel,
/// Present for Hero 7.
AverageLuminance,
/// Present for Hero 9.
CameraOrientation,
/// `Exposure time (shutter speed)`.
/// Present for Hero 5, 6, 7, 9.
ExposureTime,
/// `Face Coordinates and details`.
/// Present for Hero 6, 7, 8, 9.
FaceCoordinates,
/// `GPS (Lat., Long., Alt., 2D speed, 3D speed)`.
/// Present for Hero 5, 6, 7, 8, 9, 10, 11.
Gps5,
/// Present for Hero 11
Gps9,
/// `Gravity Vector`.
/// Present for Hero 8, 9, 10, 11.
GravityVector,
/// `Gyroscope`. Present for Hero 7, 8, 9, 10, 11.
Gyroscope,
/// `Gyroscope (z,x,y)`. Present for Hero 5, 6
GyroscopeZxy,
/// `Image uniformity`.
/// Present for Hero 7, 8, 9.
ImageUniformity,
/// `ImageOrientation`.
/// Present for Hero 9.
ImageOrientation,
/// Present for Hero 9
LrvFrameSkip,
/// Present for Hero 9
MicrophoneWet,
/// Present for Hero 9
MrvFrameSkip,
/// Present for Hero 7
PredominantHue,
/// Present for Hero 7
SceneClassification,
/// Present for Fusion
SensorGain,
/// Present for Hero 7, 9
SensorIso,
/// Present for Hero 7
SensorReadOutTime,
/// Present for Hero 7, 9
WhiteBalanceRgbGains,
/// Present for Hero 7, 9
WhiteBalanceTemperature,
/// Present for Hero 9
WindProcessing,
Other(String),
}

impl DataType {
/// Returns stream name (`STNM`) specified in gpmf documentation as a string slice.
/// Returns stream name (`STNM`) as specified inside GPMF.
pub fn to_str(&self) -> &str {
match self {
// Confirmed for Hero 7, 8, 9, 11
Expand Down
77 changes: 28 additions & 49 deletions src/content_types/gps/gps.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,25 @@
use rayon::{slice::ParallelSlice, prelude::ParallelIterator};
use time::{PrimitiveDateTime, ext::NumericalDuration, macros::datetime, Duration};

use crate::{
FourCC,
GpmfError,
Stream,
Timestamp, content_types::primitivedatetime_to_string, gpmf
};
use time::PrimitiveDateTime;
use crate::content_types::primitivedatetime_to_string;

use super::GoProPoint;

/// Gps point cluster.
/// Gps point cluster, converted from `GPS5` or `GPS9`.
#[derive(Debug, Default, Clone)]
pub struct Gps(pub Vec<GoProPoint>);

impl Gps {
// pub fn from_gpmf(gpmf: &Gpmf) {

// }

pub fn len(&self) -> usize {
self.0.len()
}

pub fn iter(&self) -> impl Iterator<Item = &GoProPoint> {
self.0.iter()
}

pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut GoProPoint> {
self.0.iter_mut()
}

pub fn into_iter(self) -> impl Iterator<Item = GoProPoint> {
self.0.into_iter()
}
Expand All @@ -53,17 +42,16 @@ impl Gps {

/// Returns the start of the GPMF stream as `PrimitiveDateTime`.
/// Returns `None` if no points were logged or if no points with minimum
/// level of satellite lock were logged. Defaults to 3D lock if `min_gps_fix` is `None`.
/// level of satellite lock were logged. Defaults to 2D lock if `min_gps_fix` is `None`.
pub fn t0(&self, min_gps_fix: Option<u32>) -> Option<PrimitiveDateTime> {
let first_point = self
.iter()
.find(|p| p.fix >= min_gps_fix.unwrap_or(2))? // find first with satellite lock (default 2D)
.find(|p| p.fix >= min_gps_fix.unwrap_or(2))? // find first with satellite lock
.to_owned();

Some(
// subtract timestamp relative to video timeline from datetime
first_point.datetime
- first_point.time
first_point.datetime - first_point.time,
)
}

Expand All @@ -73,8 +61,8 @@ impl Gps {
pub fn t0_as_string(&self, min_gps_fix: Option<u32>) -> Option<String> {
self.t0(min_gps_fix)
.and_then(|t| primitivedatetime_to_string(&t).ok())
}
}

pub fn t_last_as_string(&self) -> Option<String> {
self.last()
.and_then(|p| primitivedatetime_to_string(&p.datetime).ok())
Expand All @@ -86,25 +74,28 @@ impl Gps {
/// the device will log zeros or possibly latest known location with a
/// GPS fix of `0`, meaning both time and location will be
/// wrong.
///
///
/// `min_gps_fix` corresponds to satellite lock and should be
/// at least 2 to ensure returned points have logged a position
/// that is in the vicinity of the camera.
/// Valid values are 0 (no lock), 2 (2D lock), 3 (3D lock).
/// On Hero 10 and earlier (devices that use `GPS5`) this is logged
/// in `GPSF`. Hero11 and later deprecate `GPS5` the value in GPS9
/// should be used instead.
///
///
/// `min_dop` corresponds to [dilution of position](https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)).
/// For Hero10 and earlier (`GPS5` devices) this is logged in `GPSP`.
/// For Hero11 an later (`GPS9` devices) DOP is logged in `GPS9`.
/// A value value below 500 is good
/// according to <https://github.com/gopro/gpmf-parser>.
pub fn prune(self, min_gps_fix: u32, _min_dop: Option<f64>) -> Self {
// GoPro has four levels: 0, 2, 3 (No lock, 2D lock, 3D lock)
Self(self.0.into_iter()
.filter(|p| p.fix >= min_gps_fix)
.collect::<Vec<_>>())
Self(
self.0
.into_iter()
.filter(|p| p.fix >= min_gps_fix)
.collect::<Vec<_>>(),
)
}

/// Prune points mutably if `gps_fix_min` is below specified value,
Expand All @@ -114,41 +105,29 @@ impl Gps {
/// the device will log zeros or possibly latest known location with a
/// GPS fix of `0`, meaning both time and location will be
/// wrong.
///
///
/// `min_gps_fix` corresponds to satellite lock and should be
/// at least 2 to ensure returned points have logged a position
/// that is in the vicinity of the camera.
/// Valid values are 0 (no lock), 2 (2D lock), 3 (3D lock).
///
/// Valid values are:
/// - 0 (no lock)
/// - 2 (2D lock)
/// - 3 (3D lock)
///
/// On Hero 10 and earlier (devices that use `GPS5`) this is logged
/// in `GPSF`. Hero11 and later deprecate `GPS5` the value in GPS9
/// should be used instead.
///
///
/// `min_dop` corresponds to [dilution of position](https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)).
/// For Hero10 and earlier (`GPS5` devices) this is logged in `GPSP`.
/// For Hero11 an later (`GPS9` devices) DOP is logged in `GPS9`.
/// A value value below 500 is good
/// A value below 500 is good
/// according to <https://github.com/gopro/gpmf-parser>.
pub fn prune_mut(&mut self, min_gps_fix: u32, _min_dop: Option<f64>) -> usize {
// GoPro has four levels: 0, 2, 3 (No lock, 2D lock, 3D lock)
let len1 = self.len();
self.0.retain(|p| p.fix >= min_gps_fix);
let len2 = self.len();
return len1 - len2
return len1 - len2;
}
}

pub enum GpsLock {
None,
Lock2D,
Lock3D
}

impl GpsLock {
pub fn num(&self) -> u8 {
match &self {
GpsLock::None => 0,
GpsLock::Lock2D => 2,
GpsLock::Lock3D => 3,
}
}
}
2 changes: 2 additions & 0 deletions src/content_types/gps/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Structs and methods for processing GPS data (`GPS5` and `GPS9`).

mod gps;
mod point;

Expand Down
6 changes: 1 addition & 5 deletions src/content_types/gps/point.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
use std::borrow::BorrowMut;

use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use time::{PrimitiveDateTime, macros::datetime, ext::NumericalDuration, Duration};

use crate::{Timestamp, FourCC, Stream, GpmfError, content_types::primitivedatetime_to_string};
use crate::{FourCC, Stream, GpmfError, content_types::primitivedatetime_to_string};

/// Point derived from GPS data stream.
#[derive(Debug, Clone)]
Expand Down
3 changes: 1 addition & 2 deletions src/content_types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! Processing and conversion of various kinds of sensor data.
//! Currently only GPS is supported. The rest will be added gradually.
//! Processing of GPS and various kinds of sensor data.

use time::{PrimitiveDateTime, format_description};

Expand Down
4 changes: 2 additions & 2 deletions src/content_types/sensor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Covers GoPro 3D sensors. Supported sensors are:.
//! Covers GoPro 3D sensors. Supported sensor data:
//! - Accelerometer
//! - Gyroscope
//! - Gravity
//! - Gravity Vector

mod sensor_data;
mod sensor_type;
Expand Down
Loading

0 comments on commit 4ed45d4

Please sign in to comment.