Toy video codec designed as a successor to Pretty Good Video
Goals are to improve:
Create pfv_rs::enc::Encoder, feed in frames & audio, and then write to file:
```rs use pfv_rs::enc::Encoder;
let mut enc = Encoder::new(width, height, framerate, samplerate, audiochannels, quality, numthreads);
// feed in frames as VideoFrames (1 keyframe every 15 frames) for (idx, frame) in &myframes.iter().enumerate() { if idx % 15 == 0 { enc.encodeiframe(frame); } else { enc.encode_pframe(frame); } }
// append audio to be encoded (interleaved L/R samples) enc.appendaudio(myaudio);
// write file to disk let mut outvideo = File::create("myvideo.pfv").unwrap(); enc.write(&mut out_video).unwrap(); ```
Create pfvrs::dec::Decoder and call advancedelta every frame, passing in elapsed time since previous frame, and handling video & audio using closures:
```rs use pgv_rs::dec::Decoder;
let mut dec = Decoder::new(myfile, numthreads).unwrap();
while dec.advancedelta(deltatime, &mut |frame| { // do something with returned &VideoFrame }, &mut |audio| { // do something with returned &[i16] }).unwrap() {} ```
Alternatively, you may call advance_frame to skip directly to the next frame without passing a delta parameter. The signature is the same.
Both functions will also return Ok(true) if there is more data to read in the file, or Ok(false) if the decoder has reached the end of the file.
Video frame encoding is pretty standard as far as video codecs go. Frames are split into 16x16 macroblocks, which are further divided into 8x8 subblocks. Each subblock is DCT transformed & quantized to reduce the number of bits required for storage. Coefficients are further compressed using entropy coding.
PFV also employs 4:2:0 chroma subsampling - so U and V chroma planes are half the size of the Y plane on each axis.
There are three kinds of frames: drop frames, i-frames, and p-frames.
Audio packets are heavily based on the QOA audio format, due to its ease of implementation, decent audio quality vs compression ratio, and high decoding performance.