![Latest Version]
![docs]
![BSD-2]
[](https://github.com/ralfbiedert/openh264-rust)
Idiomatic and low-level bindings for OpenH264, converting between these two in Rust:
Decode some H.264 bitstream to YUV: ```rust use openh264::decoder::Decoder; use openh264::nal_units;
let h264in = includebytes!("../tests/data/multi_512x512.h264"); let mut decoder = Decoder::new()?;
// Split H.264 into NAL units and decode each. for packet in nalunits(h264in) { let yuv = decoder.decode(packet)?; } ```
And encode the same YUV back to H.264: ```rust use openh264::encoder::{Encoder, EncoderConfig};
let config = EncoderConfig::new(512, 512); let mut encoder = Encoder::with_config(config)?;
// 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-unknown-linux-gnu
| ✅ | ✅ |
| x86_64-apple-darwin
| ✅ | ✅ |
| aarch64-linux-android
| 🆗1 | - |
| wasm32-unknown-unknown
| ❌1,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 i9-9900K, Windows 10, single threaded de- and encoding:
``` -- Default -- test decodeyuvsingle1920x1080 ... bench: 9,243,380 ns/iter (+/- 497,200) test decodeyuvsingle512x512cabac ... bench: 1,841,775 ns/iter (+/- 53,211) test decodeyuvsingle512x512cavlc ... bench: 2,076,030 ns/iter (+/- 7,287) test encode1920x1080fromyuv ... bench: 38,657,620 ns/iter (+/- 793,310) test encode512x512from_yuv ... bench: 6,420,605 ns/iter (+/- 1,003,485)
-- Feature asm
--
test decodeyuvsingle1920x1080 ... bench: 4,265,260 ns/iter (+/- 89,438)
test decodeyuvsingle512x512cabac ... bench: 901,025 ns/iter (+/- 21,902)
test decodeyuvsingle512x512cavlc ... bench: 1,618,880 ns/iter (+/- 53,713)
test encode1920x1080fromyuv ... bench: 13,455,160 ns/iter (+/- 862,042)
test encode512x512from_yuv ... bench: 4,011,700 ns/iter (+/- 2,094,471)
-- Color Conversion -- test convertyuvtorgb1920x1080 ... bench: 7,226,290 ns/iter (+/- 110,871) test convertyuvtorgb512x512 ... bench: 907,340 ns/iter (+/- 28,296) ```
decoder
- Enable the decoder. Used by default.encoder
- Enable the encoder. Used by default.backtrace
- Enable backtraces on errors (requires nightly)asm
- Enable assembly. Only supported on x86
and ARM
, requires nasm
installed.How does openh264-sys2
differ from openh264-sys
?
We directly ship OpenH264 source code and provide simple, hand-crafted compilation via cc
in build.rs
. Ouropenh264-sys2
crate should compile via cargo build
out of the box on most platforms, and cross-compile via cargo build --target ...
as
long as the environment variable CXX
is properly set.
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 (almost, see below) as simple as pulling their latest source,
copying it into that directory, and manually removing all "resource" files. We probably should have a script to strip that folder automatically ...
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.
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.
However, if only some frames fail the most likely reasons are your endoder injecting some special packets or simply transmission errors. In other words, unless you have a very controlled setup you simply 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 for some input then it would be a bug
if we can't. However, any stream / frame it fails on is pretty much a wontfix for us.
Ideally the embedded upstream should be pristine. That said, the following patches have been applied to fix Valgrind issues and crashes on some platforms:
decoder.cpp
- removed if (pCtx->pDstInfo) pCtx->pDstInfo->iBufferStatus = 0;
which seems to write to previously deallocated memory.Help with upstreaming them would be appreciated.
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:
asm
feature for 2x - 3x speed boost.