This resource is going through a major rewrite due to the release of editable images. This post will stay as an “archive” of the old method used. Watch for new replies to know when the new version is released.
Summary
After a lot of time and hard decisions, I decided to rewrite all of the codebase and finally do what I deemed impossible. I had this idea a very long time ago, but I just couldn’t implement it correctly. As of the release of editable images, this is no longer a headache to think about. We have a very performant writePixels() method that can be used. Sadly, at the current stage of this beta feature, it cannot be used inside an actual game, but hopefully in the future this will change and we will get to see it happen. The way it was supposed to work is that we have an encoder that will read the binary data of the video and convert it to readable values that we can use for our colors. The problem with that is that the only way to make it readable is to convert it to a string. This topic is very complex, so I won’t go into a lot of details here. The easiest way you could think of is to simply put each bit in a string and then convert that back using a simple algorithm. This is indeed the easiest way, but we will have an overhead of 192 times more than it actually should be. Computers were made to read binary code; a bit is the smallest value it reads; it’s simply a 0 or a 1. Yes or no. A byte is 8 bits, which allows it to store values from 0-255 in decimal numbers. Instead of saving each bit, we can store a single byte per color value. This makes 1 pixel equal to 3 bytes instead of 192. RGB (red, green, and blue) has exact decimal values from 0-255. I am still looking for better optimization and compression methods that will help reduce it even further. The first time I tried it, I turned a 30kb image into 3gb of data (somehow). Currently, as you will see in the videos, I have significantly reduced that and optimized it for 0–15 second 480p videos. I will not post any of the code here, but you can follow the Github repository, which was deleted btw. Read the new update at the bottom of this message. As of writing this, the latest commit doesn’t include any of the Python code I wrote. I am moving my codebase to C++, and that’s for a good reason (it’s faster and works better with binary instructions). If you want to see any of the old bad code, look for older commits. With that being said, I want to archive this resource since it won’t be needed anymore. Also, as of the beta release of the actual video implementation by Roblox, none of this might be needed for developers. I am not really happy with what they are doing, but hopefully in the future it will change. 2K Robux for some 60 seconds of semi-good quality, no alpha channel, and only a single auido track? That is just pointless to say; Roblox has got to do better than that. I will stop yapping about it now and just show you what I have so far with a video example.
Personally, I think this was the best attempt of all I had:
Here is another attempt with a higher resolution (please note that the audio is out of sync since it’s playing from Spotify and it’s not the full video )
sing along pa pa ra pa pa back to time pa pa ra pa pa - Album on Imgur
UPDATES
2024-03-03T21:00:00Z
Summary
This is still being worked on. After a few months I realized how complex this idea is.
I am currently testing with some other compression methods. If what I have in my mind ends up working it will be safe to say I am making a “roblox video codec”.
I don’t want to explain the whole idea here, you can watch a video here.
In short, I am now trying to implement an actual video format and not a copy of gifs or motion jpegs. I am currently experimenting with delta frames. The whole idea is that we only store the pixels that have changed since the last frame, this way we reduce the size of each frame by a lot. Especially for more static videos, this will work perfectly, just like real videos do. Here is a small showcase.
Showcase
The very first frame of our video:
The next frame that we want to compress:
The delta (difference) between the first frame and the second frame: (black spots are parts that didn’t change)
The decoded image only using the very first frame and the delta: (identical to the original)
Anyone looking for the old repository - it was deleted.
I want to start over from scratch and write better code than before.
I will try to finish this stupid project sooner.
If you ask why there are random parts that are on the delta, but visually they didn’t change, well that’s an artifaction from the video. The only issue with videos are these randomly changing chunks. The higher the quality of the recording - the better output you are going to get. The video I used was low resolution and bitrate on purpose (not really, but yeah).
2024-03-18T21:00:00Z
Summary
updated repository with new workflow
published it as a package on wally
implemented CI/CD
will add unit tests with TestEz in the future
the preview game has been updated to be used with the new workflow and auto deployment. you can still watch the videos in the post though.
nothing much. just a small update on the progress.
i figured out quite a lot during the process.
i am actively working on finally getting a reliable, fast decoder. the “codec” will use something similar to the MJPEG standard, just with my own twists.
please note that the source code in the repository itself is currently empty and nothing makes sense. i am working hard to get it done sooner. for any contributions/questions hit me up here or on discord. i will rarely update this post as of now on.
2024-04-19T21:00:00Z
Summary
Well, it’s been almost a month since the last update. I don’t want to keep this dead so let’s sum up what I was doing for this time.:
- Completely rewritten code structure
- A whole new optimization idea that has a potential to save 50% of the decoding time. The module now initializes and prepares all frames. It completely rewrites how the data is represented in the buffer so it’s easier for me to read it. Here I actually can get the static memory usage below the initial video file size.
- New debugging and error handling.
- Insanely fast speeds due to the new data structure, it is now mainly based on buffers. If I’m correct, it is doing 21mb/s of readind/writing from/to a buffer(s). 3k frames initialized in about 7.3 seconds.
- A ton of new math optimizations that I can use. I made a discovery of this IDCT (Inverse Discrete Cosine Transform) fornula which promises to be insanely fast compared to the traditional DCT III (3) formula listed on Wikipedia.
- I scraped the idea of trying to write the code to be ran in parallel. If stuff don’t go that well I will do something about it, but for now it will be ran in serial.
- I also quit the idea of trying to make “delta frames”. It doesn’t work effectively with the JPEG format.
- More and more code optimizations, more comments and better readability.
The repository commit history dead. I don’t make any commits, but I am making changes and a lot of progress!
Trying to understand low level computer science and math concepts you won’t even learn in university it’s quite the hassle to try and speedrun it. For the past month I have probably rewritten the code structure at least 5 times, each new version teaching me something new and helping me improve as a programmer. I am not planning to do it again, but it might be required for some part of the code if I am going to use parallel. I am sure this old project that I started as a joke now has a lot of potential to inspire others to power their imagination.
Also let me remind you, this is a knockoff lego game running a trash language called lua. Speeds like these are insane and just shows how something trash becomes great over time. Big respect to the creators and maintainers of lua. I am going to end this update with a screenshot of how the debug and error handling looks like. Do note that some of the information there can be straight up nonsense (most of the frame data). There is no decoding of the pixel data yet, the limit and goal is 1 / 60 (0.016s). There are many other optimizations I used, but haven’t mentioned. When I finish this project I will make a breakdown and review every single optimization I used. That’s all I had to say for today.
Oh, also… Totally forgot, I made a logo for the project. I know it looks bad, don’t tell me that
Are you interested in a full breakdown of the optimizations and techniques used?