DEV Community

yue xing
yue xing

Posted on

A video got bigger after re-encoding? Check bits per pixel before you touch codec settings

A 1080p clip of 2,030,217 bytes went through HandBrake's Fast 1080p30 preset (x264, RF 22) and came out at 5.85 MB. A preset called "Fast" sounds like it should at worst leave a small file alone, so the natural reaction is to go hunting for a setting you got wrong. That is the wrong place to start. The first thing to look at is how many bits the input already spends on each pixel.

Bits per pixel is bitrate with the frame size divided out

The number is the video bitrate divided by (width × height × frame rate), in bits per pixel per frame, bpp for short. A bitrate on its own says little because a 1080p frame has 2.25 times the pixels of a 720p one, so two files at a similar Mbps can sit at very different quality levels. CRF mode aims at a quality level, not at a bitrate.

I tested this by encoding three real clips and one synthetic test pattern at nine CRF levels each, then re-encoding every result once with x264 CRF 23, preset medium, audio removed. That is 36 inputs. I'm not sure the shape holds beyond this setup, so read the table as a description of these runs only.

Input bpp Files Output ÷ input (size) Files that grew
below 0.08 24 1.34× to 6.67× 24 of 24
0.08 to 0.13 4 0.91× to 0.96× 0 of 4
0.16 and above 8 0.24× to 0.63× 0 of 8

Quality did not make up for the growth. One 1080p moose clip, pre-encoded at CRF 36, scored SSIM 0.9205 against the master. After the second pass it scored 0.9180 at 3.76 times the size. The extra bytes were spent preserving damage that was already there.

Why Mbps alone misleads

The same 36 runs show where bitrate breaks. A 1080p clip at 2.74 Mbps grew to 1.48× on re-encoding (bpp 0.044). A 720p clip at only 1.95 Mbps grew to 1.34× (bpp 0.070). The 720p file has the lower bitrate but the higher bpp, 0.070 against 0.044, and it grew less. Across the four contents, the first input that stopped growing sat at 0.089 to 0.133 bpp, but at 3.1 to 5.5 Mbps, depending on resolution. Lined up by bpp, the four contents agree with each other; lined up by Mbps, they do not. No content stopped growing below 0.07.

Reading the numbers with ffprobe

Everything needed is in one ffprobe call. This is a real run on a 10-second 720p H.264 clip, renamed input.mp4:

$ ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,width,height,r_frame_rate,bit_rate:format=duration,size,bit_rate -of default=nw=1 input.mp4
codec_name=h264
width=1280
height=720
r_frame_rate=30/1
bit_rate=732591
duration=10.000000
size=920021
bit_rate=736016
Enter fullscreen mode Exit fullscreen mode

732,591 ÷ (1280 × 720 × 30) is 0.0265, far under any line I would draw. Re-encoding that file with x264 CRF 23 turned 920,021 bytes into 2,183,646, a 2.37× jump. On the five WebM clips below, the stream-level bit_rate came back N/A, so I used the container figure (size × 8 ÷ duration). It includes audio and runs a little high, from 1.7% to 22% on these clips.

Checking five full clips against the 0.10 line

Picking 0.10 as a skip line, no file in the 36 that would have saved 10% or more was skipped. I then ran the five full-length real clips through the same CRF 23 pass (three of them are the sources the 36 test files were cut from, so this is a check, not independent data). The 0.032 bpp clip came out at 2.805×. The other four, at 0.113, 0.239, 0.264 and 0.279 bpp, came out at 0.831×, 0.560×, 0.664× and 0.348×. HandBrake's Fast 1080p30 preset went the same direction on the smallest and the 0.113 one, at 2.88× and 0.98×. When a file grows, I now check bpp first, then ask whether it was worth re-encoding at all, and only then touch preset and CRF.

Where this stops being true

The threshold belongs to the target setting, not to the video. With CRF 28 as the target the line moved down to roughly 0.06, but that came from the same runs and I did not test it separately. The 36-point run is H.264 into H.264. H.265, AV1 and bitrate-targeted modes are untested, and so are phone originals; all five real clips are VP8 or VP9 WebM files from Wikimedia Commons. Whether 0.10 is useful for your files, I don't know. It is a place to start measuring.

Handling several files at once

For the five full clips I also used the video compression page of ImgIng https://imging.ai/ in a desktop browser, which accepts several files at once and has quality tiers. Its default smart tier kept the original for four of the five, by its own rule rather than by bpp. Its phone and tablet pages only offer image compression, so video needs a computer.

Sample videos: Wikimedia Commons, re-encoded and trimmed, so modified. Moose by the road.webm, Forza1000, CC BY-SA 4.0. A Demonstration of Disabled People June 2018 1.webm, DGW, CC BY-SA 3.0. Worldwide Demonstration – March 2021 Amsterdam.webm, Karen Eliot, CC BY-SA 2.0. Demonstration of Ethiopian residents in Israel, July 2019.webm, Israel Police, CC BY-SA 3.0. Demonstration in Al-Zabadani, 23 March 2012.webm, Allfor Syria, CC BY 3.0.

Top comments (0)