Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions src/modules/qt/filter_gpsgraphic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,26 +633,44 @@ static void process_filter_properties(mlt_filter filter, mlt_frame frame)
/ 1000);
}

//checks if a new file is selected and if so, does private_data cleanup and calls qxml_parse_file
//checks if a new file is selected and if so, does private_data cleanup and calls q_parse_file
//+ computes some one time pdata values
static void process_file(mlt_filter filter, mlt_frame frame)
{
private_data *pdata = (private_data *) filter->child;
mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
char *filename = mlt_properties_get(properties, "resource");

//if there's no file selected just return
if (!filename || !strcmp(filename, ""))
return;
char auto_filename[PATH_MAX] = {0};
bool try_auto_filename = false;

//if there's no file selected, try to find one, and just return if failure or already tried
if (!filename || !strcmp(filename, "")) {
if (pdata->checked_gps_companion)
return;

//get the parent clip's path
mlt_producer producer = mlt_producer_cut_parent(mlt_frame_get_original_producer(frame));
char *clip_path = mlt_properties_get(MLT_PRODUCER_PROPERTIES(producer), "resource");
bool ret = q_auto_gps_file(clip_path, auto_filename);
pdata->checked_gps_companion = true;
Comment thread
ddennedy marked this conversation as resolved.
Resolved

if (ret) {
filename = auto_filename;
try_auto_filename = true;
} else
return;
}

//check if the file has been changed, if not, current data is ok, do nothing
if (strcmp(pdata->last_filename, filename)) {
// mlt_log_info(filter, "Reading new file: last_filename (%s) != entered_filename (%s), swap_180 = %d\n", pdata->last_filename, filename, swap);
default_priv_data(pdata);

strncpy(pdata->last_filename, filename, sizeof(pdata->last_filename) - 1);
pdata->last_filename[sizeof(pdata->last_filename) - 1] = '\0';

if (qxml_parse_file(filter_to_gps_data(filter)) == 1) {
if (q_parse_file(filter_to_gps_data(filter)) == 1) {
if (try_auto_filename)
mlt_properties_set_string(properties, "resource", filename);
get_first_gps_time(filter_to_gps_data(filter));
get_last_gps_time(filter_to_gps_data(filter));

Expand All @@ -665,6 +683,8 @@ static void process_file(mlt_filter filter, mlt_frame frame)
//store name in pdata or it'll retry reading every frame if bad file
strncpy(pdata->last_filename, filename, sizeof(pdata->last_filename) - 1);
pdata->last_filename[sizeof(pdata->last_filename) - 1] = '\0';
if (try_auto_filename)
pdata->checked_gps_companion = true;
}
}
}
Expand Down Expand Up @@ -740,7 +760,7 @@ mlt_filter filter_gpsgraphic_init(mlt_profile profile,
mlt_properties_set_int(properties, "show_now_text", 1);
mlt_properties_set_double(properties, "angle", 0);
mlt_properties_set_int(properties, "thickness", 5);
mlt_properties_set(properties, "rect", "10% 10% 30% 30%");
mlt_properties_set(properties, "rect", "75% 75% 20% 20%");
mlt_properties_set_int(properties, "show_grid", 0);
mlt_properties_set(properties, "legend_unit", "");
mlt_properties_set_int(properties, "draw_individual_dots", 0);
Expand Down
24 changes: 10 additions & 14 deletions src/modules/qt/filter_gpsgraphic.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct s_gps_data_bounds

namespace {

typedef struct
struct private_data
{
gps_point_raw *gps_points_r; //raw gps data from file
gps_point_proc *gps_points_p; //processed gps data
Expand All @@ -55,31 +55,27 @@ typedef struct
double bg_img_scaled_width, bg_img_scaled_height;
QRectF bg_img_matched_rect;
int swap_180;
} private_data;
bool checked_gps_companion;
};

} // namespace

typedef enum {
gspg_location_src = 0,
gpsg_altitude_src,
gpsg_hr_src,
gpsg_speed_src
} gpsg_data_sources;
enum gpsg_data_sources { gspg_location_src = 0, gpsg_altitude_src, gpsg_hr_src, gpsg_speed_src };

typedef enum {
enum gpsg_data_subids {
gpsg_latitude_id = gspg_location_src,
gpsg_longitude_id = gpsg_latitude_id + 100
} gpsg_data_subids;
};

typedef enum {
enum gpsg_graph_types {
gpsg_2d_map_graph = 0,
gpsg_crop_center_graph,
gpsg_speedometer_graph
//gpsg_ladder_graph, //was thinking a vertical ruler/gauge thing for altitude, couldn't design something that actually looks good
//gpsg_compass_graph //probably easy to adapt from speedometer but not really that important to be worth the extra code
} gpsg_graph_types;
};

typedef enum {
enum gpsg_color_styles {
gpsg_color_by_solid = 0,
gpsg_color_by_solid_past_future,
gpsg_color_by_solid_past,
Expand All @@ -93,7 +89,7 @@ typedef enum {
gpsg_color_by_speed_max100,
gpsg_color_by_grade_max90,
gpsg_color_by_grade_max20
} gpsg_color_styles;
};

struct s_base_crops
{
Expand Down
5 changes: 3 additions & 2 deletions src/modules/qt/filter_gpsgraphic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ schema_version: 7.2
type: filter
identifier: gpsgraphic
title: GPS Graphic
version: 4
version: 5
copyright: Meltytech, LLC
creator: Daniel F
license: LGPLv2.1
Expand All @@ -17,7 +17,8 @@ parameters:
- identifier: resource
title: GPS File/URL
description: >
The fullpath of file containing location (GPS) data. Supported extensions: .gpx, .tcx.
The fullpath of the file containing location (GPS) data. Supported extensions: .gpx, .tcx .txt
(see the gpstext yml for .txt support details)
type: string
required: yes
readonly: no
Expand Down
39 changes: 30 additions & 9 deletions src/modules/qt/filter_gpstext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

namespace {

typedef struct
struct private_data
{
gps_point_raw *gps_points_r; //raw gps data from file
gps_point_proc *gps_points_p; //processed gps data
Expand All @@ -41,7 +41,8 @@ typedef struct
char last_filename[PATH_MAX]; //gps file fullpath
char interpolated;
int swap_180;
} private_data;
bool checked_gps_companion;
};

} // namespace

Expand Down Expand Up @@ -129,7 +130,6 @@ static int get_next_token(char *str, int *pos, char *token, int *is_keyword)
*/
static int64_t extract_offset_time_ms_keyword(char *keyword)
{
//mlt_log_info(NULL, "extract_offset_time_keyword: in keyword: %s\n", keyword);
char *end = NULL;
if (keyword == NULL)
return 0;
Expand Down Expand Up @@ -601,22 +601,41 @@ static void process_file(mlt_filter filter, mlt_frame frame)
private_data *pdata = (private_data *) filter->child;
mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
char *filename = mlt_properties_get(properties, "resource");
char auto_filename[PATH_MAX] = {0};
bool try_auto_filename = false;

if (filename == NULL)
filename = mlt_properties_get(properties,
"gps.file"); /* for backwards compatibility with v1 */

//if there's no file selected just return
if (!filename || !strcmp(filename, ""))
return;
//if there's no file selected, try to find one, and just return if failure or already tried
if (!filename || !strcmp(filename, "")) {
if (pdata->checked_gps_companion)
return;

//get the parent clip's path
mlt_producer producer = mlt_producer_cut_parent(mlt_frame_get_original_producer(frame));
char *clip_path = mlt_properties_get(MLT_PRODUCER_PROPERTIES(producer), "resource");
bool ret = q_auto_gps_file(clip_path, auto_filename);
pdata->checked_gps_companion = true;
Comment thread
ddennedy marked this conversation as resolved.
Resolved

if (ret) {
filename = auto_filename;
try_auto_filename = true;
} else
return;
}

//check if the file has been changed, if not, current data is ok, do nothing
if (strcmp(pdata->last_filename, filename)) {
// mlt_log_info(filter, "Reading new file: last_filename (%s) != entered_filename (%s), swap_180 = %d\n", pdata->last_filename, filename, swap);
default_priv_data(pdata);

strncpy(pdata->last_filename, filename, sizeof(pdata->last_filename) - 1);
pdata->last_filename[sizeof(pdata->last_filename) - 1] = '\0';

if (qxml_parse_file(filter_to_gps_data(filter)) == 1) {
if (q_parse_file(filter_to_gps_data(filter)) == 1) {
if (try_auto_filename)
mlt_properties_set_string(properties, "resource", filename);
get_first_gps_time(filter_to_gps_data(filter));
get_last_gps_time(filter_to_gps_data(filter));

Expand All @@ -628,6 +647,8 @@ static void process_file(mlt_filter filter, mlt_frame frame)
//store name in pdata or it'll retry reading every frame if bad file
strncpy(pdata->last_filename, filename, sizeof(pdata->last_filename) - 1);
pdata->last_filename[sizeof(pdata->last_filename) - 1] = '\0';
if (try_auto_filename)
pdata->checked_gps_companion = true;
}
}
}
Expand Down Expand Up @@ -718,7 +739,7 @@ mlt_filter filter_gpstext_init(mlt_profile profile, mlt_service_type type, const
"Altitude: #gps_elev#m\n\n"
"GPS time: #gps_datetime_now# UTC\n"
"GPS location: #gps_lat#, #gps_lon#");
mlt_properties_set_string(my_properties, "geometry", "10%/10%:80%x80%:100%");
mlt_properties_set_string(my_properties, "geometry", "5% 50% 45% 45% 100%");
mlt_properties_set_string(my_properties, "family", "Sans");
mlt_properties_set_string(my_properties, "size", "26");
mlt_properties_set_string(my_properties, "weight", "400");
Expand Down
42 changes: 39 additions & 3 deletions src/modules/qt/filter_gpstext.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ schema_version: 7.2
type: filter
identifier: gpstext
title: GPS Text
version: 9
version: 10
copyright: Meltytech, LLC
creator: Daniel F
license: LGPLv2.1
Expand Down Expand Up @@ -81,8 +81,44 @@ parameters:

- identifier: resource
title: GPS File/URL
description: >
"The fullpath of file containing location (GPS) data. Supported extensions: .gpx, .tcx."
description: |
The fullpath of the file containing location (GPS) data. Supported extensions: .gpx, .tcx. .txt.
Note: while .gpx and .tcx are international standards, .txt files do not generally contain info
on how and what GPS details are storing, yet many devices (mainly dashcams) use them anyway and
record positions in a human-readable format.
Also note that while text files usually have the .txt extension, any input file that is not
ending in .gpx or .tcx will be passed to the generic text_parser, so as long as it is text (i.e.
not binary) and it has one entry per line, there is a good chance it will work.
At this point there are 2 modes for parsing text files:
1) Automatic regex:
* This was introduced as a no hassle alternative for just loading a reasonable formatted
plaintext file. It only looks for datetime and a latitude/longitude pair.
* It searches for this pattern: yyyy*MM*dd*HH*mm*ss[.sss] (optional 1-3 digit miliseconds) and
if found, it parses it as the date-time; any non-digit separators can exist between these fields,
so both 2026/10/23_12:23:34 and 20261023122334 are found correctly.
* It then searches for latitude (and after it, a longitude) with a regex matching 0.1234 to
123.45678910 (so 1-3 digits followed by a dot then 4+ digits). Optionally starts with NSEW or +-.
* See the q_parse_txt() function in gps_parser.cpp for the exact QT regexes used).
2) Manual format line:
* Regex is limited and can fail, so if you want extra fields or if your date is non standard
(like month before day) there is another option: you need to manually edit the .txt file and
insert a format string like the one below as the first line:
#delimiter=" " datetime="yyyy/MM/dd" datetime="hh:mm:ss" latitude longitude speed skip heading altitude
which corresponds to:
2025/06/12 02:45:01 N:45.123456 E:26.123456 0.0 km/h 0.00 72.50 10 x:-4.13 y:0.27 z:0.49
* The "#delimiter=" keyword is mandatory at the start, and it will treat everything between the ""
as the delimiter. Common values are space (" ") and comma (",").
* datetime= is a special keyword that takes an argument between "" which will be passed to
QDateTime::fromString, so use the patterns QT accepts.
* For date and time, there are also the "date" and "time" keywords that will attempt to separately
match yyyy*MM*dd and hh*mm*ss*[.ms], "datetime" which will do them together, and datetimeiso which
will match ISO 8601 extended format ("2026-10-23T18:25:20.739" with optional timezone).
* Supported keywords: datetime= datetimeiso datetime date time lat lon speed alt ele head bear hr
heart cad temp pow.
* Note: any format/keyword name not recognized will be skipped along with it's corresponding column
value. In my example above, the "skip" keyword simply skips over the unit which follows the speed.
* Also note that everything after the last keyword is skipped so you don't need to bother with the
entire line in the file.
type: string
required: yes
readonly: no
Expand Down
Loading
Loading