Over the year I contributed to an AV1 encoder written in rust.
Here a small tutorial about what is available right now, there is still lots to do, but I think we could enjoy more user-feedback (and possibly also some help).
Setting up
Install the rust toolchain
If you do not have rust installed, it is quite simple to get a full environment using rustup
$ curl https://sh.rustup.rs -sSf | sh
# Answer the questions asked and make sure you source the `.profile` file created.
$ source ~/.profile
Install cmake, perl and nasm
rav1e uses libaom for testing and and on x86/x86_64 some components have SIMD variants written directly using nasm
.
You may follow the instructions, or just install:
– nasm (version 2.13 or better)
– perl (any recent perl5)
– cmake (any recent version)
Once you have those dependencies in you are set.
Building rav1e
We use cargo, so the process is straightforward:
## Pull in the customized libaom if you want to run all the tests
$ git submodule update --init
## Build everything
$ cargo build --release
## Test to make sure everything works as intended
$ cargo test --features decode_test --release
## Install rav1e
$ cargo install
Using rav1e
Right now rav1e has a quite simple interface:
rav1e 0.1.0
AV1 video encoder
USAGE:
rav1e [OPTIONS] --output
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-I, --keyint Keyframe interval [default: 30]
-l, --limit Maximum number of frames to encode [default: 0]
--low_latency low latency mode. true or false [default: true]
-o, --output Compressed AV1 in IVF video output
--quantizer Quantizer (0-255) [default: 100]
-r
-s, --speed Speed level (0(slow)-10(fast)) [default: 3]
--tune Quality tuning (Will enforce partition sizes >= 8x8) [default: psnr] [possible
values: Psnr, Psychovisual]
ARGS:
Uncompressed YUV4MPEG2 video input
It accepts y4m
raw source and produces ivf
files.
You can configure the encoder by setting the speed
and quantizer
levels.
The low_latency
flag can be turned off to run some additional analysis over a set of frames and have additional quality gains.
Crav1e
While ave and gst-rs will use the rav1e crate directly, there are a number of software such as handbrake or vlc that would be much happier to consume a C API.
Thanks to the staticlib
target and cbindgen is quite easy to produce a C-ABI library and its matching header.
Setup
crav1e is built using cargo, so nothing special is needed right now beside nasm
if you are building it on x86/x86_64
.
Build the library
This step is completely straightforward, you can build it as release
:
$ cargo build --release
or as debug
$ cargo build
It will produce a target/release/librav1e.a
or a target/debug/librav1e.a
.
The C header will be in include/rav1e.h
.
Try the example code
I provided a quite minimal sample case.
cc -Wall c-examples/simple_encoding.c -Ltarget/release/ -lrav1e -Iinclude/ -o c-examples/simple_encoding
./c-examples/simple_encoding
If it builds and runs correctly you are set.
Manually copy the .a
and the .h
Currently cargo install
does not work for our purposes, but it will change in the future.
$ cp target/release/librav1e.a /usr/local/lib
$ cp include/rav1e.h /usr/local/include/
Missing pieces
Right now crav1e
works well enough but there are few shortcomings I’m trying to address.
Shared library support
The cdylib
target does exist and produce a nearly usable library but there are some issues with soname support. I’m trying to address them with upstream, but it might take some time.
Meanwhile some people suggest to use patchelf or similar tools to fix the library after the fact.
Install target
cargo
is generally awesome, but sadly its support for installing arbitrary files to arbitrary paths is limited, luckily there are people proposing solutions.
pkg-config
file generation
I consider a library not proper if a .pc
file is not provided with it.
Right now there are means to extract the information need to build a pkg-config
file, but there isn’t a simple way to do it.
$ cargo rustc -- --print native-static-libs
Provides what is needed for Libs.private
, ideally it should be created as part of the install step since you need to know the prefix
, libdir
and includedir
paths.
Coming next
Probably the next blog post will be about my efforts to make cargo able to produce proper cdylib
or something quite different.
PS: If somebody feels to help me with matroska in AV1 would be great 🙂