Unverified Commit 54d18124 authored by ZettaScript's avatar ZettaScript
Browse files

Doc, Readme

parent 6feace04
......@@ -2,7 +2,7 @@
name = "syeve"
version = "0.1.0"
authors = ["tuxmain <tuxmain@zettascript.org>"]
license = "AGPL v3"
license = "AGPL-3.0-only"
repository = "https://framagit.org/ZettaScript/syeve"
description = "Simple yet efficient video encoding (lossless streaming codec)"
edition = "2018"
......
......@@ -2,6 +2,12 @@
This is a lossless video codec, aiming at screen capture and anything else you'd want to format in PNG instead of JPEG. It is the equivalent of PNG for video.
As PNG, there are two steps: filtering, and compressing.
The filter transforms the pixels into the differences between adjacent pixels. This way adjacent pixels with the same color have the value 0, and linear gradients become constant series. The filtered image is now easier to compress with a conventional algorithm.
The difference with PNG is that the filter also takes the difference across time, so that if the frames are almost the same, they will be full of zeros.
## Example
Run a P2P video-conferencing example:
......@@ -12,6 +18,17 @@ Run a P2P video-conferencing example:
(change `127.0.0.1` to the server address)
```rust
// Let `input_raw_frame: Vec<u8>` be an RGB24 bitmap of size 1920*1080
let mut buf = Vec::new();
let mut encoder = syeve::Encoder::new((1920, 1080), 3, syeve::Compression::Brotli(4), 30);
encoder.encode(&mut input_raw_frame, &mut buf).unwrap();
let mut decoder = syeve::Decoder::new();
let output_raw_frame = decoder.decode(&buf).unwrap().pixels;
```
## Motivation
Lossy video formats are very efficient, but:
......@@ -23,16 +40,19 @@ Lossy video formats are very efficient, but:
## Status
Do not use it in production yet. Protocol may change.
**unstable, not benchmarked, not fuzz-tested**... but promising 😎
* [ ] Divide image into individual blocks
* [ ] Remove unsafe code
* [ ] Optional lossy optimization? (posterization)
* [ ] Benchmark
* [ ] More tests (frame loss)
* [ ] Avoid allocation on decoding
Single frame encoding is faster than with `image-rs/image-png` (thanks to SIMD optimization).
Any help with optimization (potentially lossy) or benchmark or else would be greatly appreciated. (PR/issue/email welcome)
## Protocol
The protocol is extremely simple: comparable to PNG, but each frame depends on the previous frame.
......@@ -61,6 +81,8 @@ The first frame should have frame number to zero. Frame number must be increment
* [The case of the missing SIMD code, Larry Bank, 2021](https://optidash.ai/blog/the-case-of-the-missing-simd-code)
* [libpng SSE2 implementation](https://github.com/glennrp/libpng/blob/a37d4836519517bdce6cb9d956092321eca3e73b/intel/filter_sse2_intrinsics.c)
[Donate on LiberaPay](https://liberapay.com/tuxmain)
## License
CopyLeft 2021 Pascal Engélibert
......
......@@ -2,7 +2,7 @@
name = "conference"
version = "0.1.0"
authors = ["tuxmain <tuxmain@zettascript.org>"]
license = "AGPL v3"
license = "AGPL-3.0-only"
repository = "https://framagit.org/ZettaScript/syeve"
description = "Screen sharing example for syeve"
edition = "2018"
......
//! # Simple yet efficient video encoding
//!
//! This is a lossless video codec, aiming at screen capture and anything else you'd want to format in PNG instead of JPEG. It is the equivalent of PNG for video.
//!
//! As PNG, there are two steps: filtering, and compressing.
//!
//! The filter transforms the pixels into the differences between adjacent pixels. This way adjacent pixels with the same color have the value 0, and linear gradients become constant series. The filtered image is now easier to compress with a conventional algorithm.
//!
//! The difference with PNG is that the filter also takes the difference across time, so that if the frames are almost the same, they will be full of zeros.
//!
//! ⚠ **unstable, not benchmarked, not fuzz-tested**... but promising 😎
//!
//! ```rust
//! let mut buf = Vec::new();
//! let mut encoder = syeve::Encoder::new((640, 480), 3, syeve::Compression::Brotli(4), 30);
//! let mut decoder = syeve::Decoder::new();
//!
//! for i in 0..10 {
//! let mut frame: Vec<u8> = (0..640*480*3).map(|j| ((i+j)%256) as u8).collect(); // dummy frame
//! let frame_bak = frame.clone();
//!
//! encoder.encode(&mut frame, &mut buf).unwrap();
//!
//! // [...] Transfer `buf` to decoder (e.g. UDP or file storage or avian carrier)
//!
//! let frame = decoder.decode(&buf).unwrap().pixels;
//!
//! assert_eq!(frame, frame_bak);
//!
//! buf.clear();
//! }
//! ```
mod filter;
use std::{
......@@ -8,10 +41,13 @@ use std::{
#[cfg(feature = "deflate")]
pub use deflate::Compression as Deflate;
/// Compression algo
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Compression {
/// From 0 (faster) to 11 (better)
Brotli(u32),
Brotli(
/// From 0 (faster) to 11 (better)
u32,
),
#[cfg(feature = "deflate")]
Deflate(deflate::Compression),
}
......@@ -107,6 +143,7 @@ impl Encoder {
self.size
}
/// Encode raw frame `pixels` into `buf`
pub fn encode<W: Write>(&mut self, pixels: &mut [u8], mut buf: W) -> Result<(), EncodeError> {
assert_eq!(pixels.len(), self.old_pixels.len());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment