Ripping PAL media
How to rip PAL optical media so that it plays properly in NTSC environments
Fixing PAL Speed-Up in The World at War: A Practical FFmpeg Workflow
Introduction
I recently set out to rip a specific version of The World at War — the most recent UK Blu-ray release. This version preserves the original 4:3 aspect ratio, which in my opinion is better than trying to crop the image to fit 16:9 and losing significant visual content. However, it comes with a well-known issue: PAL speed-up when played on NTSC systems.
The goal wasn’t just to compress or re-encode the files — it was to correct playback speed and pitch, while preserving as much fidelity as possible for streaming via tools like Plex or Jellyfin.
The Problem: PAL Speed-Up
The UK version of the series is mastered at 25 frames per second (PAL), while film-originated content is typically 23.976 fps (NTSC/film rate).
This results in:
- Video playing ~4% too fast
- Audio pitch being noticeably higher
- Shorter runtime than intended
While subtle, the pitch shift is especially noticeable in narration-heavy content like The World at War.
The Goal
The objectives for this project were:
- Restore correct playback speed (23.976 fps)
- Fix audio pitch and timing
- Make streaming via Plex/Jellyfin possible and look/sound normal
Preserve:
- All audio tracks (including surround)
- All subtitle streams (text + PGS)
- Re-encode video efficiently using x265
- Produce files suitable for Plex direct streaming
- Maintain archival-quality output
Early Challenges
At first glance, this seems simple: slow the video down and adjust audio. In practice, several issues came up:
- Audio Sync Drift
Initial attempts led to issues that were discovered the longer you watched an episode and checking the different available audio streams:
- Audio gradually falling out of sync
- Mismatched durations between streams
- Incorrect Audio Processing
Some approaches:
- Adjusted timestamps but not pitch
- Resampled incorrectly
- Or didn’t affect all audio streams
- Container and Codec Constraints
The source used DTS-HD Master Audio, which:
- Cannot be modified without full decode/re-encode
- Breaks if timing is altered directly
The Approach
The final solution involved treating video and audio independently but consistently.
🎬 Video Correction
The video is slowed down using a presentation timestamp adjustment:
1
2
-vf "setpts=25/23.976*PTS"
-r 24000/1001
These flags addressed:
- Expanding runtime by ~4%
- Converting playback rate to film standard
🎧 Audio Correction
Audio required a more careful approach.
The working solution:
1
-filter:a "asetrate=48000*0.95904,aresample=48000"
This flag does two things:
asetratelowers playback rate (and pitch) by ~4%aresamplebrings audio back to a standard sample rate (48kHz)
The result:
- Correct pitch
- Correct duration
- Proper sync with adjusted video
🔊 Why FLAC?
Because DTS-HD MA cannot be preserved after timing changes, audio is:
- Decoded to PCM
- Processed
- Re-encoded as FLAC
FLAC was chosen because:
- It is lossless
- Supports multi-channel audio (5.1, 7.1)
- Is widely supported by Plex and modern clients
This means:
- No quality loss from the original master
- Only the timing changes, not fidelity
📝 Subtitle Preservation
All subtitle streams were preserved using:
1
2
-map 0
-c:s copy
This includes:
- Text subtitles (SRT/ASS)
- Image-based subtitles (PGS)
Final Encoding Pipeline
The full FFmpeg command used:
1
2
3
4
5
6
7
8
9
10
11
12
ffmpeg -i input.mkv \
-map 0 \
-c:v libx265 \
-preset slow \
-crf 20 \
-vf "setpts=25/23.976*PTS" \
-r 24000/1001 \
-x265-params "hdr-opt=1:repeat-headers=1" \
-c:a flac \
-filter:a "asetrate=48000*0.95904,aresample=48000" \
-c:s copy \
output.mkv
Batch Processing the Series
To process the entire series, a simple Bash script loops over all episodes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for file in input/*.mkv; do
ffmpeg -i "$file" \
-map 0 \
-c:v libx265 \
-preset slow \
-crf 20 \
-vf "setpts=25/23.976*PTS" \
-r 24000/1001 \
-x265-params "hdr-opt=1:repeat-headers=1" \
-c:a flac \
-filter:a "asetrate=48000*0.95904,aresample=48000" \
-c:s copy \
"converted/$(basename "$file")"
done
Performance Considerations
x265 encoding is CPU-intensive.
In my case:
- A 20-core desktop handled encoding efficiently
- Running multiple parallel jobs improved throughput
I have a k3s cluster in my homelab rack, mostly comprised of older dual-core i5 NUCs and a single Skylake era E3 Xeon with an Nvidia P400 that runs all of my storage and used to run Plex/Jellyfin in a KVM VM. I determined that distributing this across a Kubernetes cluster was not worth the complexity due to:
- High I/O overhead
- Poor parallelization of single encodes
- My desktop is just so much more powerful that the NUCs or the old Xeon with an equally old GPU
Output Results
| Metric | Before | After |
|---|---|---|
| File size | 9–10 GB | ~3–5 GB |
| Frame rate | 25 fps | 23.976 fps |
| Audio pitch | High | Correct |
| Audio codec | DTS-HD MA | FLAC (lossless) |
| Subtitles | Preserved | Preserved |
Observations
During encoding, FFmpeg outputs messages like:
1
Starting new cluster due to timestamp
These are normal and relate to how the MKV container structures data. They are not errors.
Conclusion
Correcting PAL speed-up is not just a cosmetic fix, it restores the content to its intended presentation.
Key takeaways:
- Audio must be resampled correctly, not just retimed
- DTS-HD MA cannot survive timing changes, but FLAC is a perfect archival replacement
- x265 requires tuning to balance size and encoding time
- FFmpeg is powerful—but unforgiving without precise parameters
The end result is a set of files that:
- Preserve the original 4:3 presentation
- Play at the correct speed and pitch
- Are efficient for storage and streaming
- Maintain near-archival-quality audio and video
If you’re working with PAL content, this workflow is a potential way to play it on NTSC systems the way it was intended to be experienced.