dart_vp8 0.3.0
dart_vp8: ^0.3.0 copied to clipboard
Pure-Dart VP8 video codec (RFC 6386). Byte-exact decoder on all 62 official VP8 conformance vectors, plus an experimental VP8 encoder. IVF + WebM demuxers, IVF + WebM writers; no native code, no dart: [...]
dart_vp8 #
Pure-Dart VP8 video codec (RFC 6386). Correctness-focused reference
port of the upstream libvpx. No SIMD, no platform plugins, no
dart:io dependency in the library.
Status #
| Component | Status |
|---|---|
| Decoder | Stable. Byte-exact on all 62 official conformance vectors |
| IVF + WebM demuxers | Stable; auto-detect, Cues seeking, streaming WebM reader |
| WebM + IVF writers | Stable |
Encoder (encoder.dart) |
Experimental. Conformant bitstream; RD pipeline evolving |
Decoder conformance #
All 62 official VP8 conformance vectors from libvpx's
kVP8TestVectors list decode byte-exact against the upstream
reference (MD5 of the raw I420 output, every frame, every vector):
| Suite | Vectors | Status |
|---|---|---|
vp80-00-comprehensive |
18 | ✔ pass |
vp80-01-intra |
4 | ✔ pass |
vp80-02-inter |
4 | ✔ pass |
vp80-03-segmentation |
22 | ✔ pass |
vp80-04-partitions |
3 | ✔ pass |
vp80-05-sharpness |
10 | ✔ pass |
vp80-06-smallsize |
1 | ✔ pass |
| Total | 62 | ✔ pass |
Plus 14 robustness tests covering malformed / truncated / corrupt input.
Features #
- Pure Dart, zero runtime dependencies.
- Decodes any conforming VP8 stream: key + inter frames, all four MV
partitionings (16x16, 16x8, 8x16, 4x4 SPLITMV), B_PRED intra, multi-
token-partition (1 / 2 / 4 / 8), full segmentation with per-segment
Q / LF deltas, normal + simple loop filter at all sharpness levels,
hidden reference frames (
show_frame=0). - Minimal IVF demuxer + writer, a WebM/Matroska demuxer (V_VP8 video
tracks) with
Cues-based seeking, a streaming WebM reader for chunked input, and aWebmWriterfor muxing raw VP8 frames into.webmfiles. UseVp8Readerto auto-detect IVF or WebM. - Library imports only
dart:typed_data— runs on the VM, AOT, and Flutter Web.
Install #
dependencies:
dart_vp8: ^0.3.0
Decoding #
import 'dart:io';
import 'dart:typed_data';
import 'package:dart_vp8/dart_vp8.dart';
void main(List<String> args) {
final bytes = Uint8List.fromList(File(args.single).readAsBytesSync());
// Auto-detects IVF (.ivf) or WebM (.webm) from the magic bytes.
final reader = Vp8Reader(bytes);
final decoder = Vp8Decoder();
while (true) {
final pkt = reader.nextPacket();
if (pkt == null) break;
final out = decoder.decodeBytes(pkt.data);
if (!out.isShown) continue; // hidden / alt-ref reference
// out.y, out.u, out.v are Uint8List planes at strides
// out.yStride and out.uvStride. Crop to out.width x out.height.
print('${out.width}x${out.height} '
'(${out.isKeyFrame ? "kf" : "inter"})');
}
}
The returned Uint8List planes alias the decoder's internal buffers
and are overwritten on the next decode() call; copy them out if you
need to keep them around.
Encoding (experimental) #
The encoder lives behind a separate import so it doesn't pull into decoder-only builds and so the experimental status is explicit:
import 'dart:io';
import 'dart:typed_data';
import 'package:dart_vp8/encoder.dart';
void main() {
const w = 176, h = 144;
final enc = Vp8Encoder(width: w, height: h, qi: 30,
keyframeInterval: 30);
final ivf = IvfWriter(width: w, height: h,
timebaseNumerator: 1, timebaseDenominator: 30);
for (var i = 0; i < numFrames; i++) {
final f = enc.encodeFrame(
srcY: yPlane, srcU: uPlane, srcV: vPlane,
srcYStride: w, srcUvStride: w ~/ 2,
forceKey: i == 0,
);
if (!f.isDropped) ivf.addFrame(f.bytes, pts: i);
}
File('out.ivf').writeAsBytesSync(ivf.finish());
}
The bitstream is RFC 6386 conformant — Vp8Decoder (and any other
compliant decoder, including libvpx's vpxdec) decodes the output
byte-exactly. Rate/quality tradeoffs continue to improve in minor
releases; the public encoder surface is intended to stay stable while
internals churn.
What the encoder ships with today: keyframe-interval scheduling, CBR rate control with frame drops, integer + sub-pel motion search (NEAREST/NEAR/NEW), GOLDEN/ALTREF reference handling, multi-token- partition output, auto loop-filter, ROI Q-delta, activity-AQ, temporal denoiser, cyclic refresh, static-MB short-circuit, and optional RD-based intra/inter mode decision.
API surface #
Decoder side — package:dart_vp8/dart_vp8.dart:
Vp8Reader/Vp8Packet— container-agnostic demuxer (IVF or WebM).IvfReader/IvfFrame— IVF-only demuxer.WebmReader/WebmFrame/WebmTrack— WebM/Matroska V_VP8 demuxer withseekToTime.WebmStreamReader— incremental WebM reader for chunked input.WebmWriter— mux a sequence of VP8 frames into a.webmfile.Vp8Decoder— stateful decoder; one instance per stream.DecodedFrame— decoded I420 output (Y, U, V planes + metadata).
Encoder side — package:dart_vp8/encoder.dart:
Vp8Encoder— stateful encoder; one instance per stream.EncodedVp8Frame— encoded bitstream + reconstructed I420 + stats.Vp8FrameStats/Vp8CumulativeStats— per-frame and aggregate encoder telemetry.IvfWriter— minimal IVF muxer.CbrRateController— pluggable constant-bitrate rate controller.TemporalDenoiser— optional pre-encode denoiser.
Lower-level primitives (boolean coder, frame header parser, IDCT/FDCT, intra/inter predictors, loop filter, etc.) are exported from the decoder library so they can be exercised in isolation by tests; most callers do not need them.
Testing #
dart test # full suite
dart test test/conformance_suite_test.dart # 62 conformance vectors
dart test test/robustness_test.dart # malformed-input fuzz
The 62 conformance .ivf / .ivf.md5 fixtures live under
test/fixtures/. Fetch them with:
bash tool/fetch_vectors.sh
(downloads ~3 MB from
storage.googleapis.com/downloads.webmproject.org/test_data/libvpx).
Benchmarking #
Decoder throughput:
dart compile exe bin/bench.dart -o bin/bench.exe
./bin/bench.exe test/fixtures/vp80-00-comprehensive-014.ivf 20
Indicative AOT throughput on a single core (dart compile exe):
| Vector | Resolution | FPS |
|---|---|---|
vp80-00-comprehensive-013 (small) |
176x144 | ~1500 |
vp80-01-intra-1411 (intra-only) |
320x240 | ~600 |
vp80-00-comprehensive-014 (SPLITMV-rich) |
176x144 | ~575 |
This is a correctness reference, not a production codec — expect a
hardware decoder or libvpx itself to be roughly an order of magnitude
faster.
An in-tree encoder vs libvpx harness (Y4M in → PSNR/bytes table out)
lives under tool/bench/ in the repository; it is not shipped with
the package.
Non-goals #
- VP9 / AV1 decoders.
- MP4 demuxer (use a separate package — WebM is supported in-tree).
- Audio decoding (Vorbis / Opus). The WebM demuxer ignores audio tracks.
- Hardware acceleration / SIMD.
- Real-time playback guarantees.
License #
BSD-3-Clause, matching upstream libvpx. The reference C source this
project ports from is libvpx
(https://chromium.googlesource.com/webm/libvpx), copyright the WebM
project authors.