My Attempts at Comparing Compression Between ffmpeg’s x264, x265 and av1 Encoders

This post assumes you have a basic understanding of how encoding a video works, and what the popular codecs are. There are many great guides on this if you want to learn about it in detail. In short, CRF compresses a video based on visual quality, rather than targeting a specific bitrate/file size. x264 is an older incredibly widely supported codec for viewing video. x265 is the newer version of x264, and is supported by any modern video player. AV1 is a codec that was announced in 2015, and had commercial hardware support released to the public in June 2022. It is the new hotness to x264’s old reliable.

I recently came across the desire to compare various compression levels for the two most popular video codecs to the most popular up and coming one. I’m a simple guy, there’s a couple of good research papers for this specific topic, so my test setup is not going be rigorous. At best, it will be representative. I wanted to see just what a difference a codec can make on a video file size using comparable quality levels. On to the setup!

The source file is a 4k x264 I had laying around with a runtime of 1 hour and 33 minutes and a bitrate of 95.5mbp. I mostly chose it due to the fact that it was filmed, and that it was similar enough to a 4k security camera output that i could reasonably expect similar or smaller (since security cameras have a lot less dynamic motion) bitrates for security footage archival purposes. If the results work out well, I may end up grabbing an arc video card, so I am not worried about encode speed for these tests.

The source video file is being converted from from 4k to 1080p. The goal isn’t to see how small I can get the file. The goal is to see how the three results compare to each other. To that end, I will also be excluding audio and subtitles from the conversion.

This website says that x264 is considered visually lossless at 18 crf, and x265 is visually lossless at 25. The ffmpeg page for av1 says that a crf of 23 matches the visual quality of x264 at 19. Since i’m looking for a quick and dirty comparison, this is good enough, especially since various sources disagree on what crf equals what quality level anyways.

Here’s my x264 ffmpeg command:

ffmpeg.exe -i source.2160p.mkv
-map 0:v:0
-map -0:a -map -0:s -map_metadata -1
-c:v libx264
-preset slower
-vf scale=w=1920:-2
-crf 18
dest.1080p.x264.mkv

Here’s my x265 ffmpeg command:

ffmpeg -i source.2160p.mkv
-map 0:v:0
-map -0:a -map -0:s -map_metadata -1
-c:v libx265
-preset slower
-vf scale=w=1920:-2
-crf 25
dest.1080p.x265.mkv

And finally, here’s my av1 command:

ffmpeg -i source.2160p.mkv
-map 0:v:0
-map -0:a -map -0:s -map_metadata -1
-c:v libsvtav1
-preset 3
-vf scale=w=1920:-2
-crf 23
dest.1080p.av1.mkv

On to the results! after an overnight encode session, or two, I ended up with the following sizes;
* the x264 encode ended up being 10.8 gigabytes with an average bitrate of 16,666kbps.
* the x265 encode ended up being 1.08 gigabytes with an average bitrate of 1,656kbps.
* the av2 encode ended up being 1.6 gigabytes with an average bitrate of 2,458kbps.

Hold on, the av1 codec is supposed to be more efficient than the other two. What gives? A relatively long check with FFMetrics later, and we have results. Here’s a great article explaining the numbers further, but in short, they check various metrics against the source material to try and get a number that matches the visual fidelity loss that encoding a video gives.

PSNR does a little math to see how much has changed from the source and approximates the human perception of reconstruction quality. The score is typically between 30 and 50, with the higher number being better.
SSIM compares brightness, contrast and structure to the original source. It’s values are between 0 and 1, with 1 being the most similar to the source video.
VMAF attempts to predicts subjective video quality based on a reference and a distorted video sequence. It is a newer algorithm developed by Netflix with the University of Southern California, University of Nantes IPI/LS2N lab, and The University of Texas at Austin Laboratory for Image and Video Engineering (LIVE). The values for it are also considered to be better the higher the number is.

All of this to say, my crf values were off, by a technically noticeable amount and I need to redo my work. The av1 file is considered best quality by all the digital algorithms I have access to, and needs to be reduced in order to match the other two codecs. But this brings me to a new problem. What is a good target range for each of these values to be considered “visually lossless”? Instead of trusting that the numbers are right, as they clearly aren’t entirely, I need to first define what my levels of bad, good enough, and visually lossless actually are. I also need to learn what a badly compressed video looks like so I can detect the less obvious but still there compression artifacts. Finally, I need to choose a new source video, because dang, these took way to long to encode on my poor computer.

Fair warning: Just like kerning, once you learn what bad encodes look like, you lose your ability to watch what most people consider to be good enough encodes without hating the video quality. If you enjoy youtube or netflix a lot, and don’t mind their compression, you are a prime candidate for getting mad at their encoding choices if you continue reading.

So, first, my new video is the 2012 blender open movie project, Tears of Steel. I grabbed the 4k source file, which is 12 minutes, 14 seconds long, 3840 pixels wide, and has an average bitrate of 73,227kbps. Instead of using the promised visually lossless crf values this time, I’m going to use the worst possible crf value to get an idea of what a badly compressed version of this video looks like. My new crf values will be 63, 51, and 51, for av1, x265, and x264 respectively.

The resulting file sizes were actually pretty amazing. The x264 file was 15.7MB, the x265 file was 8.38MB and the av1 file was 16.1MB. Essentially, the file size dropped to practically nothing for all of them. However, the x264 and x265 files were both unwatchable. You would have gained more edetail from a lossless 240p encode than what you got from these encodes. The real star was the av1 encode. Yes, it had a lot of blur around the edges of movement, and basically all of the details were removed and smeared into gradients of color, but the video itself was still very much understandable. Because the videos are so small, I feel comfortable sharing the results here without using a third party video host.

To pixel peep picture quality, I ran the following command on all the videos;

ffmpeg -i source.video -vf fps=1/60 codec%04d.png

The end results was twelve images from each video, demonstrating the various compression methods used. x264 turns everything into blocks, particularly around movement. x265 turns everything into blocks and triangles, also particularly around movement. av1 smooths out colors to cartoon levels, and also turns movements into blocks, but to a much lesser extent than the other two codecs.

In short, av1 does a very good job of compressing the video using methods that are better at hiding the compression to the human eye than the old x264/5 methods. Now that we know what extreme compression looks like, my next goal is to decide on a crf level that does a ‘good enough’ job of hiding the compression. For me, that means if I pixel peep i’ll find compression artifacts, but by and large, they won’t be obvious when just watching the video. Considering how well av1 has done so far, I won’t be surprised if its crf is a lot higher than the other two when i stop trying for better quality. I’ll encode by steps of 3 crf values, and try and pick the value that makes the most subjective sense to me.

My choices were as follows:

crfav1 KBx265 KBx264 KB
18419,261 632,079685,217 – visually lossless
21352,337390,358 – visually lossless411,439
24301,517250,426263,524 – good enough
27245,685165,079 – good enough176,919
30205,008110,062122,458
33168,19273,52886,899
36139,379 – visually lossless48,51663,214
39116,09631,67047,161
4297,365 – good enough20,63635,801
4581,80513,59827,484
4869,0449,72620,823
5158,3168,586 – worst possible16,120 – worst possible
5448,681
5739,113
6029,062
6316,533 – worst possible

av1 is tricky because it’s compression adds border pixellation, but it also slowly removes details from object. At it’s worst, this turns people into clay, and the borders into a janky mess. However, at more reasonable levels it’s actually pretty hard to notice the clay conversion effect. I personally noted compression artifacts while watching the video for av1 at a crf of 45, so I consider an av1 crf of 42 to be good enough for things like security camera footage, my grandmother’s house, or my tablet. Not good for archival, but damn good for less important things. The good enough av1 file size was 97Mb.

The x264 and x265 compression artifacts are a lot easier to find compared to av1. Check the borders of moving objects for pixellation. If it’s there, you can see the artifacts. I was unable to notice artifacts for x264 without pixel peeping at a crf level of 24. The file size for the video at that level was 263MB.

I was unable to notice artifacts for x265 without pixel peeping at the crf level of 27. The file size for the video at that level was 165MB.

Here is a slideshow of screenshots from my ‘good enough’ choices. You may notice compression in them, but with my eyes, while just playing the video, it wasn’t really something I could pick out easily, if at all.

So then, what do I consider to be visually lossless? From the results I got, I feel safe in agreeing with ffmpeg’s documentation regarding x264’s crf choice of 18 (685MB). You’ll probably want to go lower than the recommended 25 with x265, by at least three though. I couldn’t see any artifacts playing the crf 27 x265 video, but 25 is too close to that for me to confidently say it is visually lossless. You’re probably better off going with crf 21 (390MB) or 22 to consider it visually lossless.

For av1, I feel confident in saying that, even if you pixel peep, and compare it to the original frame by frame, you won’t find compression artifacts at the crf level of 36 which was just 139MB in size. Here’s some screenshots to compare the original to my visually lossless choices. Feel free to check my conclusions yourself.

Don’t feel like trusting my eyes for it? Let’s see what FFMetrics says about my choices;

That’s a lot better than my first attempt. However, just to be certain, I’m going to drop the CRF level until it reaches parity with the VAMF test.

Dang, that’s a much different crf level than my novice eyes are able to see. Maybe a better comparison method is needed? I recently found out about imgsli, which is a better image comparison tool than what ive been doing up until now. Let’s keep it simple, my visually lossless choice vs VAMF’s visually lossless number.

crfav1 KBx265 KBx264 KB
18419,261 632,079685,217 – visually lossless
21352,337390,358 – visually lossless411,439
24301,517 – VAMF visually lossless250,426263,524 – good enough
27245,685165,079 – good enough176,919
30205,008110,062122,458
33168,19273,52886,899
36139,379 – My visually lossless48,51663,214
39116,09631,67047,161
4297,365 – good enough20,63635,801
4581,80513,59827,484
4869,0449,72620,823
5158,3168,586 – worst possible16,120 – worst possible
5448,681
5739,113
6029,062
6316,533 – worst possible

After comparing them, I still stand by my choice. If you pixel peep the crf 36 and compare it to the the crf 24 results, you can see extremely minor differences in her jacket, but overall, nothing of value is actually lost in translation.

I had a lot of fun playing around with these comparisons. Hopefully, you found it interesting too.

{ Comments are closed }

Exporting Signal Messages to the Android Database

With the recent news that Signal is no longer supporting SMS messages, I found myself wanting to switch to a new sms app, while keeping my message history. The message app i’m switching to is called QKSMS and so far it has been a pretty great (not-encrypted) sms program. However, It doesn’t have my message history from signal, and it’s not as easy as pressing a button to make it happen.

Here is the process I used to transfer most of my sms messages. Unfortunately, there is not a way I know of to transfer MMS messages over. (Group messages and pictures) So it’s not perfect but it does help. First, you need to backup your current Signal message database, and also get the password for it. You can do this in your app Settings>Chats>Backup. Make your backup, and take note of the 30-digit password. It reads Left to right, top to bottom.

Next, you’ll need to grab the latest copy of signalbackup-tools. Move your signal .backup file and the signbackup-tools exe into the same folder on your to make working on them easier. I use syncthing to keep files between my pc and phone synced, but that’s because I already have it set up. you can use a usb cable just as easily.

Run the extraction command of signalbackup-tools on your signal message backup. The github page has lots more details, but we’ll need to use the following command to make import into android possible;

.\signalbackup-tools_win.exe C:\Users\user\Documents\signal-2022-10-28-15-53-22.backup 111112222233333444445555566666 –setselfid 9998885555 –exportxml signalsmshistory.xml

Make sure to adjust the location, backupfile name and password to match your setup. Also make sure to changed the selfid number to your phone number. If all goes well, you’ll end up with an xml file with all of your sms history in it. Once you have this file, copy it back to your android phone.

Before you can start using your news sms app, you’ll need to import your new xml file into the android database. I used SMS backup and restore. Install and run the app, then choose the xml file you made with the signalbackup tool. Let it import your messages.

For the last step, in the QKSMS settings page, at the bottom, there is a sync button you can press. This button imports all the messages from the android database and into QKSMS. You should now have all of your signal messages imported into your android messaging history.

{ Comments are closed }

My Combat Robot, Will Turner

My 1LB Combat Robot, Will Turner

I built a 1LB Combat Robot over the course of the past few months. It has been a lot more fun, and stressful than I ever thought it would end up being. I even managed to compete down in Texas on June 2, this year. The process to get there has been fun, and also a lot longer than I expected it to be.

It all started about eight months ago when I bought myself a 3D Printer, the Ender 3. 3D printing as a technology has always fascinated me, and when I say always, I mean for at least ten years now. It was only recently that strides have been made in the technology to allow it be much cheaper, as well as reliable enough to be used by the masses. I have also managed to find steady employment and time enough to work on my printer.

I was originally inspired to make my own combat robot by the /r/battlebots subreddit. It’s a mix of a TV show fan-base, as well as a community for amateur builders. I followed it because I am a fan of big robots destroying the crap out of each other, and was introduced to the hobby side of it.

This hobby side is what I am happy to talk about today. Battlebots as a genre is generally limited only by weight, and un-fun weapons. Things like nets and radio jamming aren’t fun to watch or fight, and so they are disallowed. The only other real limit to what can be built is your imagination. The battlebots TV show usually has robots that weigh between 60 pounds and 340 pounds. Its an awesome amount of destruction, and totally worth watching.

However, these huge bots are hard to start making, and expensive to maintain. Going all the way down to one and three pound robots is a lot easier, and also a lot less expensive. This is where my 3D printer comes in. It is not only viable, it is actually often done where a robot uses 3D printed materials as their robot body / base. And thus; the seed of my idea was planted. I have a 3D printer, why not make my own tiny robot to fight with?

Read more here

{ Comments are closed }

I Switched Webhost and Domains

So, there i was, happily browsing the internet and not actually caring about what was going on at my website. For almost a year, maybe two, or three. Then! Suddenly 000webhost, my old host, decided it was time to overhaul their old cpanel. They claimed it hadn’t changed in almost ten years. Forever in internet time. So they sent me an email about it. I didn’t actually care too much about it; at least not until i read their email completely and found out the process involved backing up my website and then restoring it to the new control panel.

It wasn’t actually that big of a deal, it just meant i needed to spend some time on my website and make sure it was all working as it should. Problems arose when i was never able to access the new control panel (they claimed the new and the old would run seamlessly together, but it didn’t). Also, as a free webhost, stuff like ftp backups and php scripts had strict file size limits and time limits too. So, i switched to an inexpensive webhost, paid for four years, and got a real domain while I was at it.

I also spent a week trying to find a good migration plugin, that worked within my old hosts limits and also did all the things i needed it to do. (Half of them don’t even support restoring from backups they create!) I felt really stupid when I noticed the built-in export function that wordpress has.

It should all be here now, if you notice something off send me an email at admin@dageek247.com or post a comment. They all go straight to my personal email and i check that hourly.

Shout out to dot.tk, they’ve hosted my old domain since february 2011, and did a fantastic job of it. I’m using their new paid domains and have high hopes for the next four years with them.

{ Comments are closed }

I commissioned an art piece

It was by Amirai of amarai.net. The theme I asked for was Avatar bending, with a focus on how powerful bending is compared to the actual people doing it. And also blue. I like blue.

Amirai - commission - downscaled

 

Quite frankly, I absolutely love the result and wholly recommend the artist to anyone interested in paying for some quality art.

{ Comments are closed }

WPA Password Verification Tool

I was going through my computer projects and realised that I never shared this one on my website. It’s a tool, coded in C++ that checks a text file for WPA/WPA2 password compatibility. It is most helpful in network security applications / pentesting when you have a password list and aren’t sure just how much of the list is actually a legitimate password.

For example, we have a text file with these contents:

Good Password
good password

Good Password 1234567890
good password 1234567890

GoodPassword
goodpassword

BadPass
badpass
badpa55

badpas™
BadPas™
B3dPas™

This is a bad password because the character length is way above the maximum limit of 63 characters, and WPA won’t allow such horrible things to exist in the first place anyways.

If we run the tool on it, we get these results:

A picture of the tool in action

 

Finally, here is the source code of the project. It should be able to be compiled with just about any compiler on any operating system.

#include <iostream>
#include <fstream>
#include <string>

int help(char *argv[]) {
std::cout << “Usage: ” << argv[0] << ” <PasswordFile> [Options]” << std::endl;
std::cout << ”  Options:” << std::endl;
std::cout << ”    -wpa  Verify password list using WPA Rules (WPA uses same rules as WPA2)” << std::endl;
//std::cout << ”    -clean    Automatically delete invalid passwords from file” << std::endl;
std::cout << ”    -goodlist Print all valid passwords” << std::endl;
std::cout << ”    -badlist  Print all invalid passwords” << std::endl;
std::cout << ”  Example:” << std::endl;
std::cout << ”    ” << argv[0] << ” passwordlist.txt -wpa -badlist” << std::endl;

return(1);
}

int does_exist(char *filetouse) {
//first check to see if the cfg file exists
FILE * pFile;
if(pFile = fopen (filetouse,”r”)) {
//the file exists
return(1);
} else {
//the file doesnt exist
return(0);
}
}

int verify(int argc, char *argv[]) {
//variables for later usage
//booleans for user options
bool wpa = false;
//bool clean = false;
bool goodlist = false;
bool badlist = false;
//strings for file reading
std::string password;
std::ifstream infile;
//strings for password statistics
int numberoflines = 0;
int numberoftolong = 0;
int numberoftoshort = 0;
int numberofbadchar = 0;
int numberofgood = 0;
int numberofempty = 0;

const char *filetouse = argv[1];

//check all the options
for (int i = 0; i < argc; i++) {
//options are -wpa -clean -goodlist -badlist
std::string options[4] = {“-wpa”,”-clean”,”-goodlist”,”-badlist”};
if(argv[i] == options[0]) {
wpa = true;
}
/*if(argv[i] == options[1]) {
clean = true;
}*/
if(argv[i] == options[2]) {
goodlist = true;
}
if(argv[i] == options[3]) {
badlist = true;
}
}

//read the file line by line and check to see if the passwords are right
infile.open(filetouse); //open the user file
while(getline(infile, password)) { //while not the end of the file
//getline(infile,password); //read the current line to std::string password

//count the lines in the password field
numberoflines += 1;

//check password
if(wpa == true) { //if checking WPA Rules
if(password == “”) { //empty line
//skip empty lines
numberofempty += 1;
} else if(password.size() > 63) {
//password is to big to be used
if(badlist == true) {
std::cout << password << std::endl;
}
numberoftolong += 1;
} else if(password.size() < 8) {
//password is to small to be used
if(badlist == true) {
std::cout << password << std::endl;
}
numberoftoshort += 1;
} else if (password.find_first_not_of(“!\”#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ “) != std::string::npos) {
//password contains a bad character
if(badlist == true) {
std::cout << password << std::endl;
}
numberofbadchar += 1;
} else {
if(goodlist == true) {
std::cout << password << std::endl;
}
numberofgood += 1;
}
}
}
infile.close();

std::cout << “Checked ” << numberoflines << ” passwords.” << std::endl;
std::cout << ”  ” << numberofempty << ” lines contained no text” << std::endl;
std::cout << ”  ” << numberoftoshort << ” lines were to short” << std::endl;
std::cout << ”  ” << numberoftolong << ” lines were to long” << std::endl;
std::cout << ”  ” << numberofbadchar << ” lines contained illegal characters” << std::endl;
std::cout << ”  ” << numberofgood << ” lines contained good passwords” << std::endl;

return(0);
}

int main(int argc, char *argv[]) {
if(argc <= 1){ //not enough options so help is shown
if(help(argv)) {
std::cout << “Fatal error. Quitting program.” << std::endl;
return(1);
} //else program is working fine
} else { //plenty of options, better check to see if they are the right ones
if(argv[1] == std::string(“help”)) {//display help
if(!help(argv)) {
std::cout << “Fatal error. Quitting program.” << std::endl;
return(1);
} //else program is working fine
} else {
if(does_exist(argv[1])){
verify(argc, argv);
} else {
std::cout << “Invalid file” << std::endl;
}
}
}
}

 

{ Comments are closed }

How I Explain Bitcoin

On a group of tropical island there are three native tribes each with their own chief and tribesmen. The first island tribe produces fruit and other agricultural foods. The second tribe is able to provide animals as well as meat. The third tribe provides cloth and small kitchen appliances.

Rather than fight and war over these essentials, the three tribe leaders have a meeting to decide the best way to trade their products. One tribe leader says that the best way is to trade in equal measures of weight. This would not work because the cloth and small kitchen appliances tribe would not be able to provide enough weight to get enough things of value.

The second tribe leader suggested they have a monthly trade of equal use between each other. One tribe supplies enough of their item to the other two tribes to last the month. While this would work between the hunters and the farmers, it would not work between the cloth and kitchen appliance tribe because kitchen appliances tend to last longer than meat and corn.

The third tribe leader suggests they use a form of currency. Thus far this is the most agreeable method, but they have a hard time picking a good item to use as money. Gold is too rare, and it was hard for them to make something easy to trade but hard to duplicate.

Then one of them has another idea. Why not go to the mainland and mine large stones to use as money? They would be hard to get, and everyone would agree to use them as trade items. The other two agree on this and the tribes finish their meeting.

The three tribes are happy to spare a few tribesmen to go and mine large stones to use as currency from the mainland, and since they are hard to get, nobody has any issue with gaining to many stones to quickly. However, moving these stones between the islands is a huge pain and a hassle to do. So rather than moving them every time someone buys a a cow or small kitchen appliance, they just decide to say that the stone in a certain spot belongs to this one guy.
This works out well for them. The tribes all agree that each stone has it’s own owner, and that the stone can change hands just by telling the other chief about the exchange. The stone never actually moves, but the trade is easily made, and all the tribes know about it.

On one particular mining trip, the boat carrying the stone and the tribesman gets caught in a storm. The tribesmen survive, but they are forced to drop the stone in the ocean. When they come back and tell the other tribes, they all agree that even though the stone is at the bottom of the ocean, the tribesmen still earned it, and it can still be used as currency. Bitcoins are like the stones. They have no real value, other than what we agree on. There is no real benefit from mining them alone, but they are usable nonetheless. Everyone has a record of who owns what bitcoin, and this record is called the block chain, or history of transfers. There are people who can mine more bitcoins, but it is a huge effort, and not always worth it.

{ Comments are closed }

SMBC Comic Challenge

So, on one of my favorite web comics I read this. The comic is about a an application a person created. The application, dubbed “Conception Connection” takes your birthday, and tells you what events may have aroused you parents when they conceived you. It makes for a great little joke at the end.

Now here is where I come in. At the end of the comic there is a red dot. If you mouse over this dot you will see the text “50 internet points to whoever makes it!”. Being challenged thus, I could not refuse and I created this. It is one of the things I am more proud of, because not only does it work, it looks good doing it. Needless to say, I am very happy with the way it turned out.

You can see the source code for the main script over here, highlighted and looking pretty. Once it has your birthday, it goes over to On This Day and takes the events they have so wonderfully made available for us. It then parses the correct html and makes it available similar to the way shown in the comic. However, the script has to go through about forty different pages looking for events that mach the date correctly, so it takes a lot of bandwidth.

That is why I emailed the owners of On This Day, and asked permission to leave it up and make available for everyone else. To my utter delight, they replied and said it was perfectly fine as long as I put a link to their website on it. Here’s the proof.

I hope you guys enjoy messing with my new toy, I know it was a lot of fun making it. I also know it’s been a little while since I posted anything worthwhile, but I do have other project ideas percolating in my head, one of which I have already started on.  Until then, I wish you all a good morning.

{ Comments are closed }

Site Issues

Hey guys, guess what happened?

 

I don’t know either. I think what happened to my site was the host (which I would still recommend) stopped my site from taking to much processor on their shared hosting. I understand. If I had a server, I wouldn’t want anyone taking more then his fair share either.

 

I think the processor hogging was caused by somebody stealing my WordPress password, or to many spam bots. whatever, I changed my passwords and added some security plugins, so it should be okay.

{ Comments are closed }