ARM64_Lab

ffmpeg 8.1.2: Switching to ARM64 did not deliver a decisive win

In this article
  1. First, I checked what the winget build really was
  2. The jobs I compared
  3. Looking at runs_s as-is
  4. The measurement method was what failed
  5. I am not changing my local setup

When I compared the x64 and BtbN ARM64 builds of ffmpeg 8.1.2, x264 medium at 720p took 3.61 seconds versus 3.28 seconds. The x64 build was only 1.10x slower.

Honestly, this was anticlimactic. When I realized that the ffmpeg.exe installed through winget was x64, I assumed it had to be slow. I pictured emulation getting in the way on Windows 11 Pro ARM64 and the native BtbN build winning straightforwardly.

The measurements were more complicated. ARM64 was a little faster for x264 medium scaled to 720p, but x64 was faster for x264 ultrafast at 1080p. In the -f null scaling-only job, ARM64 clearly won. Looking at any one job, I could have said either “native is faster” or “emulation is good enough.” The remaining numbers contradicted both stories.

The measurement date was June 30, 2026. The machine was a Microsoft Surface Pro, 11th Edition, with a Snapdragon X 12-core X1E80100 @ 3.40GHz and 32GB of memory, running Windows ARM64. It remained connected to AC power, with the default Balanced power plan unchanged. I wanted to stay close to my normal working state.

First, I checked what the winget build really was

The executable installed through winget was under Gyan.FFmpeg\ffmpeg-8.1.2-full_build. Looking at the path does not tell you whether it is x64 or ARM64. Assuming from the package name is usually a mistake, so I checked the actual file first. It was x64. That led to the question of what would happen with a native ARM64 build.

For the ARM64 build, I downloaded the winarm64-gpl zip from BtbN/FFmpeg-Builds and extracted ffmpeg.exe. This was the command I used:

curl.exe -L -s -o C:\Users\AKIRAS~1\AppData\Local\Temp\arm64lab_c\ff-arm64.zip https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-winarm64-gpl.zip

The download finished in 7.8 seconds, and the zip was 114800704 bytes. I placed the extracted ARM64 ffmpeg.exe at C:\Users\AKIRAS~1\AppData\Local\Temp\arm64lab_c\ffmpeg-arm64\ffmpeg.exe. I also generated the source with the ARM64 build. It was a synthetic 1920x1080, 30fps, 20-second testsrc2 video encoded to src.mp4 with libx264 ultrafast. Generation took 14.78 seconds, and the resulting file was 38850889 bytes. The fact that it was not live-action footage matters later.

The jobs I compared

I narrowed the jobs to three: scaling to 720p with x264 medium, x264 ultrafast at 1080p, and a scaling-oriented job that largely removes encoding and discards the result with -f null. I ran each job three times with both the x64 and ARM64 builds.

This design was rough, to be honest. The source was synthetic testsrc2, not live-action footage. Each job took only 0.52 to 5.81 seconds, so process startup and file I/O made up an unusually large share. Three repetitions were also not enough to make the medians reassuring. I still wanted to start with a small measurement.

It is not a bad way to get an initial sense of whether replacing the ffmpeg build might be worthwhile. It was nowhere near enough to judge a 10% difference. I only realized that after finishing the measurements.

Looking at runs_s as-is

Listing only the medians makes the results easier to read, but it would be dangerous here. The variation itself is part of the result, so I am showing all three runs_s values and fps_samples.

Job Build All three runs_s median_s fps_samples
x264 medium 720p x64 2.94 / 3.61 / 5.81 3.61 225 / 179 / 109 fps
x264 medium 720p ARM64 3.94 / 2.24 / 3.28 3.28 206 / 289 / 261 fps
x264 ultrafast 1080p x64 1.88 / 1.81 / 1.61 1.81 375 / 391 / 420 fps
x264 ultrafast 1080p ARM64 2.18 / 5.20 / 1.86 2.18 458 / 120 / 567 fps
scale only null x64 0.73 / 0.76 / 0.76 0.76 0 / 0 / 0 fps
scale only null ARM64 0.55 / 0.52 / 0.53 0.53 0 / 0 / 0 fps

For x264 medium 720p, x64 took 3.61 seconds and ARM64 took 3.28 seconds. x64 was 1.10x slower.

The direction was as expected, but the difference was small. One of the three runs was 2.94 seconds for x64 and another was 3.94 seconds for ARM64. If I had measured only once, I could have written the opposite conclusion. I stopped trying to declare a winner at that point.

The x264 ultrafast 1080p result was surprising. The medians were 1.81 seconds for x64 and 2.18 seconds for ARM64, with x64_slower_x at 0.83x. In other words, x64 was faster under this condition. The ARM64 fps_samples swung from 458 to 120 to 567 fps. With that spread under ostensibly identical conditions, the 2.18-second median is not especially trustworthy.

Only scale only null behaved straightforwardly. x64 took 0.76 seconds and ARM64 took 0.53 seconds, so x64 was 1.43x slower. With encoding removed and the workload focused more on scaling, the native build appeared to have an advantage. However, every fps_samples value was 0 fps, so that metric extracted from ffmpeg's output was useless.

The measurement method was what failed

The biggest problem was that the measurement unit was too short. Although the source was 20 seconds long, the jobs themselves finished in two to four seconds. That mixes ffmpeg.exe startup, opening the input file, creating the output, and the operating system's cache state.

Three repetitions were also insufficient. The ARM64 x264 ultrafast 1080p runs were 2.18 seconds, 5.20 seconds, and 1.86 seconds; the maximum was 2.80x the minimum. fps_samples also moved from 120 to 567 fps. Treating a 1.10x difference as a performance difference with that amount of variation is not defensible. I wondered why I had not prepared a longer source.

I almost made another mistake: reading native ARM64 versus x64 emulation directly as “the cost of emulation.” libx264 is an area with extensive hand-written assembly optimization, and the ARM64 and x64 builds may use different kernels in the first place. CPU instructions, the x264 implementation, ffmpeg build settings, Windows emulation, and I/O variation are all layered together. This was not a measurement that isolated translation overhead.

Until I noticed that, I was looking at the numbers with the assumption that native had to win. The numbers broke that expectation. Treating the mixed results themselves as the conclusion was the correct approach.

I am not changing my local setup

These numbers alone do not make me want to replace ffmpeg with the ARM64 build. The 3.61-versus-3.28-second result for x264 medium 720p is a small difference, and x64 wins at 1.81 seconds for x264 ultrafast 1080p. ARM64 is stronger in scale-only null at 0.53 versus 0.76 seconds, but my usual workload is not limited to that job.

So I am keeping the winget build for now. Easy package updates are also a significant benefit. Within this test, I could not conclude that x64 emulation was a clear bottleneck. In fact, Windows 11 ARM64 on the Surface Pro 11th Edition runs the x64 ffmpeg more normally than I expected. That was a little disappointing.

If I repeat this, I want to measure a long encode with live-action footage. I would use input lasting at least several minutes, increase the repetitions, and discard the first run as warm-up. As a small experiment on June 30, 2026, this was enough to put aside the expectation that switching to ARM64 would always be faster.

Benchmark Emulation
a
arm64lab — Independent publisher

Personal test notes from a Surface Pro 11th Edition with Snapdragon X Elite, used as a daily machine since May 2025. Results are based on direct measurements and do not represent any company or organization.