More video Tricks
So far, ive been doing couple of things with the action cam.
Even apply data analytics for action cams andfor karting!
Now its time for a recap on my latest video tricks.
High vs Low Bit Rate
FHD - 1080/30
With the updated firmware and high bit rate, 1080p30 UW RS
I got these files with H.265
codec:
- 38.9GB total MP4 files (every 17.2gb or 1h 12min there is a file reset)
- Bitrate 31168 kbps, with an average size of ~4.03MB/s
- Using 80% of the total battery for those ~2h 45min of video
This happened while recording at ~0C
With the updated firmware and low bit rate, 1080p30 UW RS
I got:
- 41.6GB total MP4 files (every 17.2gb or 1h 13min there is a file reset)
- Bitrate 30739 kbps, with an average size of ~3.98MB/s
- Using 93% of the total battery for those ~2h 45min of video
This happened while recording at room temperature ~20C
4K/60
Three files with a total size of 35.5GB and draining battery to 67% (-33%) for 42min and 50s video.
Recording at 4K/60fps RS+ and standard (no UW, h.265) and high bitrate.
All of this at -2C
Data Overlay with Python
I was already analyzing GoPro Metadata:

But how about adding telemetry overlays to MP4’s?
GoPro Python Metadata Overlay
Python MoviePy…
…actually uses FFMPEG, but makes it more scriptable, in theory.
DJI and GPX Overlay
And for action cams without GPS… like my DJI OA5Pro.
How about recording the route on another app and just syncing it?
Gemini Overlay explanation 📌
Building a Python tool to overlay GPX data onto MP4 videos is a challenging but rewarding project. Here’s a breakdown of the steps and libraries you’ll need:
1. Libraries:
gpxpy
: For parsing and working with GPX files.pip install gpxpy
moviepy
: For video editing and overlaying.pip install moviepy
opencv-python
(cv2): For image and video processing.pip install opencv-python
matplotlib
(optional): For creating graphs or custom visualizations.pip install matplotlib
- Potentially others: Depending on your specific visualization needs (e.g., for map tiles if you want a map background).
2. Core Logic:
- GPX Parsing: Use
gpxpy
to load and parse the GPX file. Extract the latitude, longitude, time, and optionally speed data points. - Video Handling: Use
moviepy
to load the MP4 video. - Synchronization: This is the trickiest part. You’ll need to establish a correspondence between the timestamps in your GPX data and the frames in your video. Here are a couple of approaches:
- Manual Synchronization: Allow the user to specify a start time offset or identify a specific event in both the video and the GPX data to align them. This is often the most practical.
- Automated Synchronization (Advanced): This could involve analyzing audio or video features to find matching points, but it’s significantly more complex.
- Visualization:
- Position Overlay: Use
opencv-python
to draw the GPS track on each frame of the video. You can convert latitude/longitude to pixel coordinates. Consider using a map image as a background for better visualization. - Speed Graph: Use
matplotlib
to create a graph of speed over time. Then, usemoviepy
to add this graph as an overlay on the video. - Other Data: You can overlay any data from your GPX file (heart rate, altitude, etc.) using similar techniques.
- Position Overlay: Use
- Video Composition: Use
moviepy
to combine the original video with the overlays you’ve created.
3. Code Structure (Conceptual):
import gpxpy
import gpxpy.gpx
from moviepy.editor import VideoFileClip, ImageClip, CompositeVideoClip
import cv2
import matplotlib.pyplot as plt
import numpy as np
def overlay_gpx_on_video(video_path, gpx_path, output_path):
# 1. Load video and GPX data
video = VideoFileClip(video_path)
with open(gpx_path, 'r') as gpx_file:
gpx = gpxpy.parse(gpx_file)
# 2. Synchronization (Manual example)
time_offset = float(input("Enter time offset (seconds) between video and GPX: ")) # User input
# 3. Visualization (Position Overlay Example)
frames = []
for i, track in enumerate(gpx.tracks):
for j, segment in enumerate(track.segments):
for k, point in enumerate(segment.points):
timestamp = point.time + timedelta(seconds=time_offset)
frame_time = timestamp.timestamp() - video.start # Time relative to video start
if frame_time >= 0 and frame_time <= video.duration:
frame = video.get_frame(frame_time)
# Convert lat/lon to pixel coordinates (You'll need a mapping function)
x, y = lat_lon_to_pixels(point.latitude, point.longitude) # Implement this
cv2.circle(frame, (x, y), 5, (0, 0, 255), -1) # Draw a circle
frames.append(ImageClip(frame).set_duration(1/video.fps)) #add frame to the list of frames
final_clip = concatenate_videoclips(frames)
final_clip.write_videofile(output_path, fps=video.fps)
def lat_lon_to_pixels(lat, lon): # Example (You'll need a proper projection)
# This is a VERY simplified example and won't be accurate for real-world use.
# You'll need to use a proper map projection library (e.g., pyproj) for accurate conversion.
# Assume a simple linear mapping for demonstration:
map_width = 1000 # Example
map_height = 500 # Example
min_lat = 0 # Example (Get from your map data)
max_lat = 90 # Example
min_lon = 0 # Example
max_lon = 180 # Example
x = int((lon - min_lon) / (max_lon - min_lon) * map_width)
y = int((lat - min_lat) / (max_lat - min_lat) * map_height)
return x, y
# Example usage:
video_path = "your_video.mp4"
gpx_path = "your_gpx.gpx"
output_path = "output_video.mp4"
overlay_gpx_on_video(video_path, gpx_path, output_path)
4. Key Challenges and Improvements:
- Accurate Synchronization: This is the most crucial and often the most difficult part.
- Map Projection: For accurate position overlays, you’ll need to use a proper map projection library (like
pyproj
) to convert latitude/longitude to pixel coordinates on a map image. You’ll likely want to use a tile server or download map tiles. - Performance: Processing video frame by frame can be slow. Consider optimizing your code for performance.
- User Interface: For a more user-friendly tool, you could create a graphical user interface (GUI) using libraries like
Tkinter
,PyQt
, orKivy
. - Error Handling: Add robust error handling to your code.
This detailed breakdown should give you a solid starting point for building your Python GPX overlay tool.
Remember that this is a complex project, so break it down into smaller, manageable steps.
Start with the basics (loading video and GPX, basic visualization) and then gradually add more features (synchronization, map integration, speed graphs, etc.). Good luck!
Conclusions
Its great to look back and see how far ive gone (at least compared from how I started):
FAQ
Transfering Files
Moving just MP4’s will save you ~23% of the transfer load (100gb instead of 120 for example)
#cp *.MP4 /home/jalcocert/Desktop/oa5pro/
rsync -avP *.MP4 /home/jalcocert/Desktop/oa5pro/ #it creates the folder if its not there | no overwrite
#rm *.LRF #clean if needed LRF
Quick Videos - CLI
Telemetry Data
Extracting data from action camera .MP4
files.
It all started with PhyPhox and PyRouteTracker
sudo apt-get install libimage-exiftool-perl
exiftool -ee ./GX030390.MP4
#exiftool -ee ./GX030390.MP4 > output.txt
If you do similarly with a OA5Pro video and see the metadata, the output is much more reduced
exiftool -ee ./DJI_20241008163958_0031_D.MP4 #no GPS - no party
- Make the magic happen with moviepy: https://zulko.github.io/moviepy/getting_started/updating_to_v2.html
FFMPEG
Some tricks with ffmpeg package.
No reencoding = Quick
- Simply Join: Keeping original audio and no reencoding.
###ffmpeg -i "concat:$(ls *.mp4 | tr '\n' '|')" -c copy output_video.mp4 #all from a folder
ls *.MP4 | sed "s/^/file '/; s/$/'/" > file_list.txt #add .MP4 of current folder to a list
#du -sh ./* #check their size
#Generate a video with the mentioned files (IT PRESERVES THE ORIGINAL FORMATS, BITRATE...)
ffmpeg -f concat -safe 0 -i file_list.txt -c copy output_video.mp4
ffmpeg -f concat -safe 0 -i file_list.txt -c copy /home/jalcocert/Desktop/output_video.mp4 #different folder (if you do it from OA5 to desktop you will be limited by transfer speed)
#ffmpeg -f concat -safe 0 -i file_list.txt -c:v copy -an output_video.mp4 #silenced video
#ffmpeg -i output_video.mp4 -filter:v "setpts=PTS/4" -an fast_output_video.mp4 #
- Join (Silenced) + Song
ls *.MP4 | sed "s/^/file '/; s/$/'/" > file_list.txt #add .mp4 of current folder to a list
#du -sh ./* #check their size
#generate a video from few parts
#ffmpeg -f concat -safe 0 -i file_list.txt -c copy output_video.mp4
ffmpeg -f concat -safe 0 -i file_list.txt -c:v copy -an silenced_output_video.mp4 #silenced video
#ffmpeg -i output_video.mp4 -filter:v "setpts=PTS/4" -an fast_output_video.mp4 #
#ffmpeg -stream_loop -1 -i "AETHER - Density & Time.mp3" -i silenced_output_video.mp4 -c:v copy -c:a aac -shortest output_with_song.mp4
ffmpeg -stream_loop -1 -i "TRAVELATOR - Density & Time.mp3" -i silenced_output_video.mp4 -c:v copy -c:a aac -shortest output_with_song.mp4
### 🎵 Music by:
- Extract images from video:
4ffmpeg -i input_video.mp4 -vf "select='gte(t\,120)',fps=1" -vsync vfr frame_%03d.png
ffmpeg -i DJI_20250116072852_0036_D.MP4 -vf "select='gte(t\,90)',fps=1" -vsync vfr frame_%03d.png
#ffmpeg -i DJI_20250116072852_0036_D.MP4 -vf "select='gte(t\,90)',fps=1" -vsync vfr frame_%03d.jpg
#between 2 seconds, 1fps extracts and creates a folder
#ffmpeg -i DJI_20250116072528_0035_D.MP4 -vf "select='between(t,90,105)',fps=1" -vsync vfr frame_%03d.png
mkdir -p "./$(basename DJI_20250215215547_0006_D.MP4 .MP4)" && ffmpeg -i DJI_20250215215547_0006_D.MP4 -vf "select='between(t,260,262)',fps=1" -vsync vfr "./$(basename DJI_20250215215547_0006_D.MP4 .MP4)/frame_%03d.png"
- How to reduce image quality in Linux to upload as youtube thumbnail:
#ffmpeg -i thumbnail.png -c:v libwebp -quality 80 compressed_thumbnail.webp
#ffmpeg -i PXL_20241030_115355466.jpg -q:v 3 compressed_PXL_20241030_115355466.jpg
ffmpeg -i thumbnail.png -qscale:v 2 compressed_thumbnail.jpg
Space what?
You might need some after playing around with action cams.
df -h | awk '$2 ~ /G/'
#df -h | awk '$2 ~ /G/' | sort -rh -k 2 #sorted
df -h | awk '$5 > "5G" {print $0}' #list the partitions greater than 5GB
- Have a look to the trash
#gio trash --empty
du -sh ~/.local/share/Trash/files
- Maybe unused container images?
docker builder prune
#docker system prune -a
#docker volume prune
docker image prune -a
Summary Table:
Command | Focus | Cleans | Data Loss Risk |
---|---|---|---|
docker builder prune | Build Cache | Unused build layers | Low |
docker system prune | All Unused Resources | Containers, Networks, Dangling Images, Build Cache | Medium |
docker volume prune | Unused Volumes | Volumes not attached to any container | HIGH |
docker image prune | Dangling/Untagged Images | Dangling images, optionally all untagged images | Medium |
Which one to use?
- Start with
docker system prune
if you want a general cleanup. - Use
docker builder prune
if you’re only concerned about build cache. - Be extremely careful with
docker volume prune
as it can delete data. - Use
docker image prune
with the-a
option if you want to remove all untagged images (including older versions that might be taking up space). Be sure you don’t need those older versions!