Tech Giants' Competing Standards, Out-Of-Sync Subtitles And The FOSS Remedy
Perhaps you know the situation: At one point in time you wanted to save precious storage space or you wanted to prevent the deterioration of physical media and you converted your DVD or VHS collection into files which you then stored on a hard drive or a cloud storage.
The other day, you wanted to watch one of your gems but, alas, the film is in a foreign language and when you stored it, you forgot to include the subtitles. "No problem", you think. Subtitles are easy to come by these days, e.g. from:
You download your subtitles, store them in the same directory as your film, sit down on your couch, open a bottle of wine and start to watch but, oh no, the timing seems wrong. "No problem", you think again: Most popular media players like VLC or Kodi have the option to set a time shift for the subtitle track. You fiddle a while, find the right offset, sit down again, but after a minute or two film and subtitles get out of sync again: one seems to be faster than the other!
Are The Subtitles Faulty?
Most probably not! You just have become a victim of a tech standards war from a hundred years ago: When electricity was the boom of the moment at the beginning of the XXth century and lightbulbs and electric machines started to pop up all over the place, the need for standardization arose. Unfortunately, companies didn't agree on a single one. So, in Europe, the German Allgemeine Electrizitäts Gesellschaft set the standard for AC to 220V at 50Hz, becoming the de facto global norm, whilst in the USA, Westinhouse opted for 110V at 60Hz, which can still be found in a handful of countries.
Meanwhile, the emerging film industry had set their standard to 24 photos per second. No problem at first, but when TV was invented, Germany opted for a 50 half-frames per second frequency, whilst the US, hardly surprising, went for 60 half-frames per second. At first, TV broadcating was a live event, only later, productions from the big screen were brought to the small one.
How To Take 24fps Cinema To 30/25fps TV?
The Americans decided to duplicate every fourth photo: 24/4 = 6, 6*5 = 30. The Germans, instead, decided to roll their projectors just 1/25 faster. Both systems worked but a 100 minutes film would be played on TVs following the German standard in 96 minutes. Pure TV productions also followed the standard. When you want to convert a NTSC (TV standard in the US and some other countries) production into PAL (TV standard elsewhere), you take out the duplicate images and increase the playback speed, besides other things.
Now, What Does This Means For My Subtitles?
If your video comes from a PAL source but your subtitles were time coded from a NTSC source, your subtitles will be 4% slower than the video. In contrast, if your video comes from a NTSC source but your subtitles were time coded from a PAL source, they will be displayed 4% faster than the film.
What Is The Solution?
Adjusting Video Speed
One solution could be to recode your video material with the fabulous package
If you wanted to, say, slow down your video by 4%, you could do the following:
ffmpeg -i my_video.mp4 -filter:v "setpts=1.04*PTS" my_slower_video.mp4
However, this will take quite some time and it will probably not improve the video’s quality.
Adjusting Subtitle Speed
The subtitle files `*.srt` are basically text files containing timestamps. These can easily be adjusted without any implications for the video's quality.
You can use the following script to do that:
#!/usr/bin/perl -w # © by Mina, 2020 # Free software under the GNU public licence 3.0 # https://www.gnu.org/licenses/gpl-3.0.en.html use feature 'say'; @ARGV or die "No parameters given! " . "Usage: subspeed.pl filename [+|-] > outfile.srt\n"; my ($filename, $speed) = @ARGV; die "no such file: $filename\n" unless -e $filename; die "no valid speed parameter given! Usage: subspeed.pl filename [+|-] > ". "outfile.srt\n" unless $speed =~ /\+|-/; my $speedFunc = $speed =~ /\+/ ? sub { return 25/24 * $_[0] } : sub { return 24/25 * $_[0] }; open(my $fh, '<', $filename); while(<$fh>) { unless(m/^\s*(\d+:\d\d:\d\d,\d+)\s+--\>\s+(\d+:\d\d:\d\d,\d+)\s*$/) { print; next } say join(' --> ', ( map { ms2ts($_) } ( map { &$speedFunc($_) } ( map { ts2ms($_) } ($1, $2) ) ) ) ); } close($fh); sub ts2ms { my $ts = shift; $ts =~ s/^\s+//; $ts =~ s/\s+$//; my ($h, $m, $s) = split(':',$ts); my ($sec, $ms) = split(',',$s); $ms += 1000 * ( $sec + 60 * ( $m + 60 * $h)); return $ms } sub ms2ts { my $t = shift; $t = int($t); my $ms = $t % 1000; $t = int($t/1000); my $s = $t % 60; $t = int($t/60); my $m = $t % 60; my $h = int($t/60); $ms = '0' x ( 3 - length($ms) ) . $ms; s/^(\d)$/0$1/ foreach $h, $m, $s; return "$h:$m:$s,$ms" }
Just copy it into the editor of your choice, save it as subspeed.pl
, deploy it on your system via
sudo cp subspeed.pl /usr/local/bin
and make it executable via
sudo chmod a+x /usr/local/bin/subspeed.pl
.
Now, if you want to speed up your subtitles, you just type:
subspeed.pl my\ favourite\ movie.srt - > my\ favourite\ movie.faster.srt
or, if you want to slow them down:
subspeed.pl my\ favourite\ movie.srt + > my\ favourite\ movie.slower.srt
-
stands for decrease timestamps, +
for increase timestamps.
EDIT: I had to break some lines, i.e. introduce some newlines which might make the code less readable because the lines were too long to be displayed correctly.