More video Tricks

More video Tricks

February 12, 2025

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, use moviepy 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.
  • 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, or Kivy.
  • 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

Graphic Walker UI

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

FFMPEG

Some tricks with ffmpeg package.

No reencoding = Quick

  1. 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 #
  1. 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: 
  1. 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"
  1. 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
  1. Have a look to the trash
#gio trash --empty
du -sh ~/.local/share/Trash/files
  1. Maybe unused container images?
docker builder prune
#docker system prune -a
#docker volume prune
docker image prune -a

Summary Table:

CommandFocusCleansData Loss Risk
docker builder pruneBuild CacheUnused build layersLow
docker system pruneAll Unused ResourcesContainers, Networks, Dangling Images, Build CacheMedium
docker volume pruneUnused VolumesVolumes not attached to any containerHIGH
docker image pruneDangling/Untagged ImagesDangling images, optionally all untagged imagesMedium

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!