Idiomatic and low-level bindings for OpenH264, converting between these two in Rust:
Decode some H.264 bitstream to YUV:
use openh264::decoder::Decoder;
use openh264::nal_units;
let h264_in = include_bytes!("../tests/data/multi_512x512.h264");
let mut decoder = Decoder::new()?;
// Split H.264 into NAL units and decode each.
for packet in nal_units(h264_in) {
// On the first few frames this may fail, so you should check the result
// a few packets before giving up.
let maybe_some_yuv = decoder.decode(packet);
}
And encode the same YUV back to H.264:
use openh264::encoder::Encoder;
let mut encoder = Encoder::new()?;
// Encode YUV back into H.264.
let bitstream = encoder.encode(&yuv)?;
Test results on various platforms:
Platform | Compiled | Unit Tested |
---|---|---|
x86_64-pc-windows-msvc |
✅ | ✅ |
x86_64-pc-windows-gnu |
✅ | ✅ |
x86_64-unknown-linux-gnu |
✅ | ✅ |
x86_64-apple-darwin |
✅ | ✅ |
i686-unknown-linux-gnu |
✅ | ✅ |
i686-pc-windows-msvc |
✅ | ✅ |
i686-pc-windows-gnu |
✅ | ✅ |
armv7-unknown-linux-gnueabihf |
✅ | - |
aarch64-unknown-linux-gnu |
✅ | - |
aarch64-apple-darwin |
✅ | - |
aarch64-pc-windows-msvc |
✅ | - |
aarch64-linux-android |
🆗1 | - |
wasm32-unknown-unknown |
❌2 | - |
✅ works out of the box; 🆗 the usual shenanigans required; ❌ not supported.
1 via cargo build --target <platform>
, needs CXX
set and libc++_shared.so
.
2 unclear if could ever work, investigation welcome
Tested on a Ryzen 9 7950X3D, Windows 11, single threaded de- and encoding:
-- Default --
test decode_yuv_single_1920x1080 ... bench: 5,696,370.00 ns/iter (+/- 1,892,038.50)
test decode_yuv_single_512x512_cabac ... bench: 1,103,065.00 ns/iter (+/- 49,763.50)
test decode_yuv_single_512x512_cavlc ... bench: 1,358,595.00 ns/iter (+/- 52,667.00)
test encode_1920x1080_from_yuv ... bench: 23,720,860.00 ns/iter (+/- 1,610,097.00)
test encode_512x512_from_yuv ... bench: 3,954,905.00 ns/iter (+/- 566,698.00)
-- If `nasm` available --
test decode_yuv_single_1920x1080 ... bench: 2,799,800.00 ns/iter (+/- 291,731.25)
test decode_yuv_single_512x512_cabac ... bench: 532,370.00 ns/iter (+/- 33,115.00)
test decode_yuv_single_512x512_cavlc ... bench: 1,038,490.00 ns/iter (+/- 56,953.25)
test encode_1920x1080_from_yuv ... bench: 8,178,290.00 ns/iter (+/- 1,325,363.50)
test encode_512x512_from_yuv ... bench: 1,828,287.50 ns/iter (+/- 190,976.50)
-- Color Conversion if "target-cpu=native" --
test convert_yuv_to_rgb_1920x1080 ... bench: 1,362,640.00 ns/iter (+/- 23,317.00)
test convert_yuv_to_rgb_512x512 ... bench: 174,687.50 ns/iter (+/- 7,185.75)
source
- Uses the bundled OpenH264 source; works out of the box (default).libloading
- You'll need to provide Cisco's prebuilt library.
-
How does
openh264-sys2
differ fromopenh264-sys
?We directly ship OpenH264 source code and provide simple, hand-crafted compilation via
cc
inbuild.rs
. Ouropenh264-sys2
crate should compile viacargo build
out of the box on most platforms, and cross-compile viacargo build --target ...
as long as the environment variableCXX
is properly set. -
Which exact OpenH264 version does this use?
See this file for the upstream URL and Git hash used on latest master.
-
I need to fix an important OpenH264 security hole, how can I update the library?
Cisco's OpenH264 library is contained in
openh264-sys2/upstream
. Updating is as simple as pulling their latest source, and runningupdate_openh264.sh
(and, if APIs changed,regen-bindings.bat
). -
I heard Rust is super-safe, will this make decoding my videos safe too?
No. Below a thin Rust layer we rely on a very complex C library, and an equally complex standard. Apart from Rust being a much nicer language to work with, depending on this project will give you no additional safety guarantees as far as video handling is concerned. FYI, this is not making a statement about OpenH264, but about the realities of securing +50k lines of C against attacks.
-
Feature X is missing or broken, will you fix it?
Right now I only have time to implement what I need. However, I will gladly accept PRs either extending the APIs, or fixing bugs; see below.
-
Can I get a performance boost?
- Make sure you have the command
nasm
somewhere in your PATH for your current platform (should be a single, standalone executable you don't even need to install). If found bybuild.rs
it should be used automatically for an up to 3x speed boost for encoding / decoding. - Also compile your project with
target-cpu=native
for a 3x speed boost for YUV-to-RGB conversion (e.g., check our.cargo/config.toml
how you can easily do that for your project. Note this only works if you are an application, not a library wrapping us).
- Make sure you have the command
-
Decoder::decode() returned an error, is this a bug?
Maybe. Probably not. Some encoders can write data OpenH264 doesn't understand, and if all frames fail this could either be your encoder doing exotic things, OpenH264 not having implemented a certain feature, or us having a bug.
If only some frames fail the most likely reasons are your encoder injecting some special packets or transmission errors. In other words, unless you have a controlled setup you should not terminate on the first error(s), but simply continue decoding and hope for the decoder to recover.
FWIW, we consider OpenH264's
h264dec
the reference decoder. If you can get it to emit YUV it would be a bug if we can't. However, any stream / frame it fails on is pretty much a wontfix for us. -
What's the deal with the
source
andlibloading
features?See this issue.
PRs are very welcome. Feel free to submit PRs and fixes right away. You can open issues if you want to discuss things, but due to time restrictions on my side the project will have to rely on people contributing.
Especially needed:
- BT.601 / BT.709 YUV <-> RGB Conversion
- User-pluggable and color conversions
- WASM investigation (either patch, or evidence it can't be fixed)
- Feedback which platforms successfully built on
- Faster RGB-to-YUV conversion similar to the current SIMD YUV-to-RGB one.
- Faster YUV-to-RGB conversion (done in #66)
Big shout-out to all the contributors who have filed PRs so far.
Special thanks to:
- Jannik Schleicher for addressing the long-standing issue of faster YUV-to-RGB conversion, which resulted in a more than 3x speedup.
- v0.6 - Encoder supports dynamic resolution; API cleanup.
- v0.5 - Can now use built-in source, or Cisco's prebuilt library.
- v0.4 - Update build system, remove unused API.
- v0.3 - Change some APIs to better reflect OpenH264 behavior.
- v0.2 - Added encoder;
asm
feature for 2x - 3x speed boost. - v0.1 - Initial release, decoder only.