Post

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:

  1. 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
  1. Incorrect Audio Processing

Some approaches:

  • Adjusted timestamps but not pitch
  • Resampled incorrectly
  • Or didn’t affect all audio streams
  1. 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:

  • asetrate lowers 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

MetricBeforeAfter
File size9–10 GB~3–5 GB
Frame rate25 fps23.976 fps
Audio pitchHighCorrect
Audio codecDTS-HD MAFLAC (lossless)
SubtitlesPreservedPreserved

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.

This post is licensed under CC BY 4.0 by the author.