May 1, 2016

Fixing PAL speedup and how film and video work

Filed under: Technical — Tags: , , , , — James Bunton @ 12:00 am

I have a large collection of DVDs and I live in Australia. Because of history this means most of them are in ‘PAL’ format. This means they tend to be about 4% faster than they should be, resulting shorter playing times and higher pitched voices and music.

I’m a bit of a purist. This bothers me enough that I must fix it! What follows is a somewhat lengthy explanation of how film/video works, followed by instructions on how to use my fix-pal-speedup script.

How moving pictures are stored and displayed on a screen

The first technology able to do this was film. Simply take 24 photos every second and store them on a reel. To play it back you shine a line through the reel to project the image onto a screen. This means you have 24 frames per second. This tricks your brain into thinking there is actual movement. The resolution is usually very high but is dependent on the optics of the film camera and the chemical process used in the film medium.

Most movies throughout history have been shot on film. Copies are made and distributed on reels to cinemas for playback. Because film is a physical medium it cannot transmitted into your home like with television.

A television camera is fundamentally different to a film camera. Instead of chemically recording an image it converts light into an electrical signal. This signal can be transmitted using radio waves. The frame rate of TV/Video depends on the country of origin, usually based on the local electricity supply. Australia has 240V/50Hz, so we have TV at 25fps (PAL 50 fields per second). In the USA they have 110V/60Hz and they have 30fps (NTSC 60 fields per second).

Technically PAL and NTSC refer to the colour standard, and NTSC is not exactly 60fps. I’m going to ignore these facts because they do not matter for this discussion. However when working with video you must take it into account or you’ll have audio/video sync issues!

Conversions between formats

Prior to the invention of the video tape the only way to record TV was to store it on film. There was this crazy sounding process called Kinescope where a film camera would be placed in front of a TV screen. Later you could project it onto a screen and point a TV camera at it for rebroadcast. Believe it or not this is how big networks like NBC and CBS would take record live TV shows from New York in eastern USA and delay them a few hours for rebroadcast at the right time in Los Angeles in western USA.

This process is obviously going to be lossy because of the technology involved. The invention of the video tape allowed the electrical video signal to be stored on tape directly, making everything much higher quality and easier!

However it turns out it’s also fundamentally difficult to convert between film and TV because they have different frame rates. Somehow you must take the 24 frames per second of film and stretch to PAL 25fps or NTSC 30fps. Film to NTSC conversions use an odd interpolation based approach called telecine. There are plenty of high quality algorithms for reversing this to recover the original 24fps film. Film to PAL conversions are much simpler, they simply play back the film 4% faster.

TV shows can be really messed up

Live TV must always be shot with a video camera because you cannot directly broadcast a film reel.

However many TV series are shot on film and converted to video for editing. Annoyingly this means that a TV may have original source material shot at 24fps (film), 25fps (PAL TV) or 30fps (NTSC TV). Sometimes it may even be a combination, for example lots of 90s scifi, like Star Trek, was shot on film with the special effects done directly on video. So within a single scene you may have a of 24fps film which has been telecined and 30fps video generated from special effects.

Just leave everything in its original format, Bluray is great

These days most LCD TV displays can play back content in any of the common frame rates or resolutions. However the various standards for VHS tapes and DVDs require that content be in a single frame rate. Typically everything is converted to the native frame rate for the region that content is being sold.

So if you’re living in Australia and a local DVD of a TV series originally produced in the US then you’ll be getting a converted video. Similarly the other way around. Anybody buying a film sold anywhere in the world will get a converted frame rate.

Bluray mostly fixes all this by allowing content to be distributed in its native frame rate. However annoyingly media companies don’t make blurays unless they have high definition (720p or 1080p) content. This means it can be very difficult to source clean copies of a TV series.

Also Bluray still doesn’t help for shows that have a master with ‘mixed’ frame rates. Remember the 90s scifis I mentioned earlier with both film and video in the same scenes? The only solution there is to redo all the editing and special effects from the original film, which is very expensive! This has actually been done for the Bluray release of Star Trek The Next Generation.

Film/Video standards around the world

Content Type Country of origin Format
Movie / Film Anywhere in the world 24fps, very high resolution, progressive (not interlaced)
TV PAL regions (UK, AU, etc) 25fps, 720×576 (576i), interlaced
TV NTSC regions (US) 30fps, 720×480 (480i), interlaced

How do I fix the PAL speedup then?

As I mentioned earlier, when converting content from film (24fps) and to PAL (25fps) it is usually sped up by 4%. Converting from a US TV show usually does the same thing because it goes from NTSC (30fps) and is detelecined to 24fps, then sped up to 4%. Happily this means we can usually use the same fix for PAL DVDs of both movies and US TV series.

I have a fix-pal-speedup script which does all the hard work.

Requirements:

  • Bash
  • ffmpeg with libfdk-aac support, you could easily modify the script to use a lower quality codec
  • mkvmerge
  • Input file supported by ffmpeg, must not be variable frame rate or mkvmerge will lose sync when remuxing!

How does it work? Firstly you need some simple maths, this 4% figure I keep using comes from 24 ÷ 25 = 0.96. To undo the speedup we need to slow down both the audio and video by that much.

Fortunately we don’t need to re-encode video stream, we can just tell mkvmerge to create a new file with 24fps in the header instead of 25fps. Each frame will stay on the screen just a little longer. The audio will not be so easy.

The standard for audio is a sample rate of 48000Hz. We need to slow it down by 4%. We can use the same trick as with the video stream by reading only 0.96 * 48000 samples per second, that’s 46080Hz. Fortunately ffmpeg can do this by telling it to to ignore the sample rate from the file header, we specify the input filter asetrate=46080. However we can’t save this non-standard sample rate to a file, the vast majority of players would reject it. So we now must use the ffmpeg resampling output filter to interpolate samples and bring the rate back up to 48000Hz.

Finally we recombine the audio and video into a single file using mkvmerge. The end!

13 comments

Kevin says:

what specifically do you have to do to make this work? i’m using bash for windows10 and have all the prerequisites you mentioned working, but trying to run the script returns the error: “./pal.sh: line 2: $’\r’: command not found”

Paul says:

A much simpler way to fix the PAL speedup:

1. Open VLC.
2. Go to the ‘VLC’ menu and select ‘Preferences…’
3. In the radio buttons in the lower-left corner of the window, change
‘Basic’ to ‘All’.
4. Click on ‘Input / Codecs’ in the left-hand side list.
5. In the right-hand side frame look for ‘Playback speed’ and change it to
0.96 (use a comma if your system uses that as the decimal separator).
6. Click on ‘Audio’ in the left-hand side list.
7. In the right-hand side frame disable ‘Enable time stretching audio’.
8. Click the ‘Save’ button on the lower-right corner of the window.
9. Quit and relaunch VLC.

Enjoy your PAL movie at the correct speed!

James Bunton says:

Hi @Paul,

It is indeed possible to adjust playback speed in VLC, MPlayer and mpv.

However the method above allows me to produce video files that will play anywhere at the correct speed. It also means I don’t have to remember to change the setting whenever I switch between videos which need the adjustment and those that don’t.

Since I’m transcoding all my DVDs anyway it doesn’t take much extra effort in my script to fix the playback speed once and for all :)

Paul says:

Ah I understand. So with your method you’re actually reproducing the video with the correct speed so that it can be viewed anywhere without a setting adjustment, and also on devices that are incapable of adjusting the playback speed. But I guess the average person buys TV shows on DVD to watch once anyway and aren’t interested in transcoding, so they might find it simpler to just adjust the playback speed. But then again the average person probably doesn’t even know about the 4% speed up. I personally didn’t discover it until I realised that the voice of the actors were higher pitched than in interviews. But now I’m interested in digitising my DVD collection so I’m definitely going to try this script out in the near future.

James Ainslie says:

Is it possible for you to add functionality that will stretch the vobsubs and chapter header too?

Great script.

James Bunton says:

Hi, I’m glad you found it useful!

Yeah, I’ve thought about that as well. It would definitely be possible to do the subtitles and chapters, but so far I haven’t needed them on any of the DVDs I’ve ripped.

Maybe one day :)

James Ainslie says:

I’m not too great with Bash, and even less familiar with ffmpeg/mkvtoolnix, but I gave the chapter/subtitle thing a shot and thought I’d roll it back to you in case you’d find any parts of it useful or have any comments about some glaring error.

Main points:
– All audio tracks are now converted
– This uses a slightly different approach that ditches the audio delay compensation, but I *think* delay is still preserved(?). “mkvmerge -F verbose-text” seems to have been removed on >v15 anyway.
– Subtitles are now stretched
– Chapters are now stretched
– AAC codec will fall back automatically to builtin if libfdk-aac not available
– Target framerate changed from 24fps to 23.976fps (not a vital change – due to most of my personal source material)
– AAC encoding quality increased (again, not vital – personal preference)
– Requires mkvextract (should already be present from mkvtoolnix installation)

I’d love to hear your thoughts. Hopefully it’s useful, or at least good for a laugh! And thanks again, couldn’t have pieced this together without your help.

#!/bin/bash -e

# Many DVDs released in Australia are sped up from 24fps to 25fps.
# This script reverses the procedure, correcting the audio pitch.
# The video framerate is adjusted without re-encoding. The audio is
# slowed, and encoded as AAC, preserving surround sound.

if [ -z “$1” -o -z “$2” ]; then
echo “Usage: $0 infile outfile”
exit 1
fi

#set -xe
# 23.976fps or 24000/1001
FORCEFPS=”23.976″
STRETCH=”25025/24000″
SLOWFILTER=”-filter asetrate=46034,aresample=osr=48000:resampler=soxr”

infile=”$1″
outfile=”$2″
tmpdir=”$(mktemp -d “${TMPDIR:-/var/tmp}/pal-XXXXXXXX”)”
sub_options=””
chapter_file=””
audio_file=”${tmpdir}/audio.mkv”

function mux_file {
local videotrackid=”$(get_video_trackid “$infile”)”
mkvmerge \
-o “${outfile}” \
–default-duration “${videotrackid}:${FORCEFPS}fps” \
$sub_options \
–no-audio –no-chapters “$infile” \
–sync “0:$((audiodelay / 1000000))” \
–no-chapters $audio_file \
$chapter_file
}

function get_video_trackid {
mkvmerge -i “$1″ | sed -n ‘s/Track ID \([0-9]*\): .*video.*/\1/p’
}

function encode_audio {
aac_settings=”-c:a aac -vbr 5″
if [[ `ffmpeg -version | grep libfdk-aac` ]]
then
aac_settings=”-c:a libfdk_aac -vbr 5″
fi
ffmpeg \
-i “$infile” \
-vn -sn -dn \
$SLOWFILTER \
$aac_settings \
-map 0 -max_muxing_queue_size 4000 \
“$audio_file”
}

function edit_timings {
local old_track_file=”$1″
local new_track_file=”$2″
touch “$new_track_file”
while IFS=” read -r line || [[ -n “$line” ]]; do
timestamp=`echo “$line” | \
grep -o ‘[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}.[0-9]\{3\}’ | cat`
if [ “$timestamp” ]
then
old_time=”$timestamp”
hours=$(echo $old_time | cut -f1 -d:)
minutes=$(echo $old_time | cut -f2 -d:)
seconds=$(echo $old_time | cut -f3 -d: | cut -f1 -d.)
milliseconds=$(echo $old_time | cut -f3 -d: | cut -f2 -d.)

old_ms=$(echo $hours \* 3600000 + $minutes \* 60000 + \
$seconds \* 1000 + $milliseconds | bc)
new_ms=$(echo $old_ms \* 25025 / 24000 | bc)

printf -v hh “%02d” $(echo $new_ms / 3600000 | bc)
printf -v mm “%02d” $(echo $new_ms % 3600000 / 60000 | bc)
printf -v ss “%02d” $(echo $new_ms % 60000 / 1000 | bc)
printf -v ms “%03d” $(echo $new_ms % 1000 | bc)
new_time=”$hh:$mm:$ss.$ms”

search='[0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}.[0-9]\{3\}’
replace=”$new_time”
line=`echo “$line” | sed “s/${search}/${replace}/g”`
fi
echo “$line” >> “$new_track_file”
done < "$old_track_file"
}

function fix_subtitles {
echo "Modifying subtitle track timings…"
tracks=`mkvmerge -i "$infile" | grep subtitles | \
grep -o 'Track ID [0-9]*' | sed 's/Track ID //' | cat`
while IFS= read -r track
do
if [ "$track" ]
then
echo "Stretch subtitle track $track"
sub_options="$sub_options–sync $track:0,$STRETCH "
else
echo "No subtitles found"
fi
done <<< "$tracks"
}

function fix_chapters {
echo "Modifying chapter timings…"
if [[ `mkvmerge -i "$infile" | grep Chapters` ]]
then
old_chapter_file="${tmpdir}/oldChapters.xml"
new_chapter_file="${tmpdir}/newChapters.xml"
mkvextract "$infile" chapters "$old_chapter_file"
edit_timings "$old_chapter_file" "$new_chapter_file"
chapter_file="–chapters $new_chapter_file"
else
echo "No chapters found"
fi
}

encode_audio
fix_chapters
fix_subtitles
mux_file
rm -rf "$tmpdir"

James Ainslie says:

Oops. Of course delete line 34
–sync “0:$((audiodelay / 1000000))” \

James Bunton says:

Hi @James,

I’ve just started using this again after upgrading to a newer mkvmerge. It now uses mkvmerge -i -F json with jq to extract details. I used some of your code to adjust subtitles and chapters to the correct timings.

Great work, thanks! :)

James Ainslie says:

No problem. Glad it was helpful, even if a lot of it now seems obsolete since mkvmerge v27!

Thanks again for your original script, and for the new changes.

David Daut says:

Hey, I’m a total rookie when it comes to this kind of stuff and am having some troubles figuring out how to make this work. I installed FFmpeg and mkvmerge, but when I try to copy your script into my command line nothing seems to happen. Is there another step I need to do before I copy it in, also, how do I specify the target file that I’m trying to adjust?

Sorry if I’m being thick.

James Ainslie says:

Sorry David, I realise you asked this ages ago.

You’ll want to save all of this text into a plain text file, and name it something like “pal” (no file extension) or “pal.sh”, or whatever you prefer instead of ‘pal’.

Then you need to make it executable. In the command line, go to the directory where your script file is, and use:
chmod +x [your_script]
eg.
chmod +x pal.sh

Then you can run it with:
./[your_script] [your_file]
eg.
./pal.sh ~/Movies/my_too_fast_movie.mkv

Hope that helps!

Jack says:

@James Ainslie,

I’ve adapted portions of your script and incorporated them into mine here: `https://github.com/agentspooky/fix-pal`. I’ve marked the portions adapted from your code, specifically the `edit_timings` and `fix_chapters` functions and your handling of the temp directory. Please let me know if you have any issues or concerns, or if you’d like me to add a link to somewhere besides this page.

Your work provided the missing piece I needed to complete mine; thanks!

Comments are closed.