[script] Extract and Modify mp4 frame durations

In a recent data acquisition project we used an embedded board that was producing mp4 videos with a variable video acquisition rate. While the video is nominally at 30 FPS the effective rate is around 29.5 FPS with some jitters.

The general suggestion when processing videos with OpenCV VideoCapture is to save the frame time (CV_CAP_PROP_POS_MSEC) so that each frame is associated with the real time, an important step when video annotations are expressed in time units.

The general ffmpeg way to extract durations is the following:

ffprobe -i INPUT -show_frames -show_entries frame=pkt_pts_time -of csv=p=0

On a decent machine a 30 minutes full-HD mp4 video takes 12min with ffprobe or OpenCV, and this is not acceptable.

Luckly mp4 files are easy to parse and the "stss" atom provides this information in a compact form (RLE encoding). Having not found an online solution I have prepared a Python script that extracts the timings as fast as possible (numpy.fromfile) starting from the mp4 parsing library.

The reverse operation is also possible and the script allows to specify the duration of frames in seconds at modify the mp4 by altering overall duration and the "stss" atom. An application scenario is the following:
  1. List of JPEG files with their non regular timing
  2. Use ffmpeg to generate the mp4 containing the JPEGs without recompression
  3. Use this tool to assign the correct durations
Step 2 can be performed with:

cat *.jpg | ffmpeg -f image2pipe -i - -c:v mjpeg -q:v 0  out.mp4

Step 3 can be performed with the tool as:

python setframeduration.py in.mp4 in.mp4.time --output out.mp4

Where the file in.mp4.time contains the list of duration in seconds for each file

Final notes:
  • Another use is the cheap non-linear editing of a 60 FPS videos with the creation of artificial slowdowns
  • This type of time manipulation is also possible with Matroska videos

Script on github (Python)


Popular posts from this blog

Docker for our ROS robotic overlords

cmakego: Simpler access to external libraries in CMake

Algebrical Data Types in C++