Disc::sweep, Disc::patch, Disc::copy, SweepOptions and PatchOptions have zero occurrences in src/ — recovery moved to freemkv-engine — but they were still documented in 30 places across README.md, TROUBLESHOOTING.md, six files under docs/, seven src/ doc comments and a Cargo.toml comment. README.md is the crate's GitHub front page and carried a full multi-pass code example that cannot compile. Two of the src/ references were intra-doc LINKS to deleted items ([`disc::Disc::copy`], [`disc::Disc::patch`] in scsi/mod.rs). They produced no warning on a normal `cargo doc` only because they sit on pub(crate) items; `--document-private-items` reports both, and they are gone now. The README example is deleted rather than rewritten against the engine's API: libfreemkv documenting a downstream crate's API on its own front page is the drift that produced this, and it cannot even depend on it. The src/ references become plain code spans naming freemkv_engine::recovery::* — deliberately not links, for the same reason. docs/rip-recovery.md was 202 lines about relocated code. It now documents only what this crate owns — Drive::read, SenseFamily, DiscStream's adaptive batch halving — plus the read-path design constraints, which belong with the code that enforces them, and points at freemkv-engine/src/recovery/ for the strategy. api-design.md's module tree is regenerated from the real src/disc/ and src/drive/ layouts instead of hand-patched; it had listed sweep.rs, patch.rs, mapfile.rs and read_error.rs, none of which exist. Three stale facts surfaced while rewriting and are corrected: the read timeouts are 10 s / 60 s, not the documented 1.5 s / 30 s; Drive::reset and SgIoTransport::reset no longer exist at all, so "no SCSI reset from any read path" is now stated as the stronger fact it has become; and verify_title, listed as a progress-emitting operation, was removed entirely. CHANGELOG.md keeps its references — those are the historical record of the releases that shipped the API.
161 lines
7.2 KiB
Markdown
161 lines
7.2 KiB
Markdown
[](LICENSE)
|
|
|
|
# libfreemkv
|
|
|
|
Rust library for 4K UHD / Blu-ray / DVD optical drives. Drive access, disc scanning, stream labels, AACS decryption, CSS decryption, KEYDB updates, and content reading in one crate. Drive-level unlocking is handled internally; consumers work with disc access and decryption only.
|
|
|
|
DVDs (CSS) decrypt out of the box. Blu-ray and UHD (AACS) require a `keydb.cfg` (default `~/.config/freemkv/keydb.cfg`) supplying disc-specific volume unique keys; no AACS key material is compiled in.
|
|
|
|
**12+ MB/s** sustained read speeds on BD. Drive prep (`init()`) handles unlocking internally via the `freemkv-unlock` crate — clients never see it; when no drive unlock applies, the library rips via the host-certificate AACS handshake.
|
|
|
|
Multi-lingual by design — the library outputs structured data and numeric error codes, never English text. Build any UI or localization on top.
|
|
|
|
**[Source & API](https://github.com/freemkv/libfreemkv)** · **[Technical Docs](docs/)**
|
|
|
|
Part of the [freemkv](https://github.com/freemkv) project.
|
|
|
|
## Install
|
|
|
|
Consumed by git tag (not published to crates.io):
|
|
|
|
```toml
|
|
[dependencies]
|
|
libfreemkv = { git = "https://github.com/freemkv/libfreemkv", tag = "vX.Y.Z" }
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```rust
|
|
use libfreemkv::{Drive, Disc, ScanOptions};
|
|
use std::path::Path;
|
|
|
|
// Open drive — identified via INQUIRY
|
|
let mut drive = Drive::open(Path::new("/dev/sg4"))?;
|
|
drive.wait_ready()?; // wait for disc
|
|
drive.init()?; // unlock + prep (handled internally)
|
|
drive.probe_disc()?; // probe disc surface for optimal speeds
|
|
|
|
// Scan disc — UDF, playlists, streams, AACS (all automatic)
|
|
let disc = Disc::scan(&mut drive, &ScanOptions::default())?;
|
|
|
|
for title in &disc.titles {
|
|
println!("{} — {} streams", title.duration_display(), title.streams.len());
|
|
}
|
|
|
|
// Stream pipeline — read PES frames from any source, write to any output
|
|
let opts = libfreemkv::InputOptions::default();
|
|
let mut input = libfreemkv::input("iso://Disc.iso", &opts)?;
|
|
let title = input.info().clone();
|
|
let mut output = libfreemkv::output("mkv://Movie.mkv", &title)?;
|
|
while let Ok(Some(frame)) = input.read() {
|
|
output.write(&frame)?;
|
|
}
|
|
output.finish()?;
|
|
```
|
|
|
|
### Multi-pass recovery rip
|
|
|
|
Recovery moved OUT of this crate in 1.6.0. The sweep/patch strategy, the
|
|
ddrescue mapfile, damage classification and the multipass loop now live in the
|
|
`freemkv-engine` crate as `freemkv_engine::recovery::{copy, sweep, patch}`.
|
|
|
|
libfreemkv keeps the layers underneath: the raw single-shot read
|
|
(`Drive::read`) and the SCSI-fact translation (`SenseFamily`) that the engine's
|
|
strategy is built on. The dependency runs engine → libfreemkv, so this crate
|
|
cannot call into it; front-ends get recovery from the engine directly. See
|
|
[`docs/rip-recovery.md`](docs/rip-recovery.md) for what stayed here.
|
|
|
|
## What It Does
|
|
|
|
- **Drive access** — open, identify, internal unlock + prep, speed control, eject
|
|
- **12+ MB/s reads** — auto-detects kernel transfer limits, sustained full speed
|
|
- **Disc scanning** — UDF 2.50 filesystem, MPLS playlists, CLPI clip info
|
|
- **Stream labels** — 5 BD-J format parsers (Paramount, Criterion, Pixelogic, CTRM, Deluxe)
|
|
- **AACS decryption** — transparent key resolution and content decrypt (1.0 + 2.0 bus decryption)
|
|
- **KEYDB updates** — download, verify, save from any HTTP URL (zero deps, raw TCP)
|
|
- **Content reading** — adaptive batch reads with automatic decryption
|
|
- **Stream I/O** — unified stream pipeline for reading and writing any format
|
|
|
|
### Streams
|
|
|
|
| Stream | Input | Output | Transport |
|
|
|--------|-------|--------|-----------|
|
|
| DiscStream | Yes | -- | Optical drive via SCSI |
|
|
| IsoStream | Yes | -- | Blu-ray ISO image file (read via stream pipeline; written by `freemkv_engine::recovery`) |
|
|
| MkvStream | Yes | Yes | Matroska container |
|
|
| M2tsStream | Yes | Yes | BD transport stream with FMKV metadata header |
|
|
| NetworkStream | Yes (listen) | Yes (connect) | TCP with FMKV metadata header |
|
|
| StdioStream | Yes (stdin) | Yes (stdout) | Raw byte pipe |
|
|
| NullStream | -- | Yes | Discard sink (byte counter for benchmarks) |
|
|
|
|
Streams implement a single unified `pes::Stream` trait (re-exported as `PesStream`) exposing `read()` and `write()` on one type. `input()` / `output()` resolve URL strings to PES stream instances. All URLs use the `scheme://path` format — bare paths are rejected.
|
|
|
|
### Keys
|
|
|
|
DVDs (CSS) decrypt out of the box, with no external key file needed.
|
|
|
|
Blu-rays and UHD (AACS) require a `keydb.cfg` at `~/.config/freemkv/keydb.cfg` (or passed via `ScanOptions`). No AACS key material is compiled into the binary.
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
Drive — open, identify, init, single-shot read
|
|
├── ScsiTransport — SG_IO (Linux), IOKit (macOS), SPTI (Windows)
|
|
└── unlock_bridge — private seam to the freemkv-unlock crate
|
|
(firmware / AACS cert / CSS bus-auth unlockers)
|
|
|
|
Disc — scan titles, streams, AACS/CSS state
|
|
├── UDF reader — Blu-ray UDF 2.50 with metadata partitions
|
|
├── MPLS parser — playlists → titles + clips + streams
|
|
├── CLPI parser — clip info → EP map → sector extents
|
|
├── IFO parser — DVD title sets, PGC chains, cell addresses
|
|
├── Labels — 5 BD-J format parsers (detect + parse)
|
|
├── AACS — key resolution + content decryption
|
|
├── CSS — DVD CSS (bus auth → player-key disc crack → known-plaintext title-key attack)
|
|
└── KEYDB — download + verify + save
|
|
|
|
Streams — unified PES pipeline
|
|
├── PesStream — pes::Stream: one trait, read()/write() PES frames
|
|
├── DiscStream — sectors → decrypt → TS demux → PES
|
|
├── IsoStream — ISO file → decrypt → TS demux → PES
|
|
├── MkvStream — MKV mux/demux
|
|
├── M2tsStream — BD transport stream
|
|
├── NetworkStream — TCP with FMKV metadata header
|
|
├── StdioStream — stdin/stdout pipe
|
|
└── NullStream — discard sink
|
|
```
|
|
|
|
See [docs/](docs/) for detailed technical documentation on each module.
|
|
|
|
## Error Codes
|
|
|
|
All errors are structured with numeric codes. No user-facing English text — applications format their own messages.
|
|
|
|
| Range | Category |
|
|
|-------|----------|
|
|
| E1xxx | Device errors (not found, permission) |
|
|
| E2xxx | Profile errors (unsupported drive) |
|
|
| E3xxx | Unlock errors (failed, signature) |
|
|
| E4xxx | SCSI errors (command failed, timeout) |
|
|
| E5xxx | I/O errors |
|
|
| E6xxx | Disc format errors |
|
|
| E7xxx | AACS errors |
|
|
| E8xxx | KEYDB update errors |
|
|
| E9xxx | Stream / mux errors (URL, PES, ISO, pipeline, demux) |
|
|
|
|
## Platform Support
|
|
|
|
| Platform | Status | Backend |
|
|
|----------|--------|---------|
|
|
| Linux | Supported | SG_IO ioctl |
|
|
| macOS | Supported | IOKit SCSITask |
|
|
| Windows | Supported | SPTI |
|
|
|
|
## Contributing
|
|
|
|
Run `freemkv info disc:// --share` with the [freemkv CLI](https://github.com/freemkv/freemkv) to capture your drive's identity for contribution. Drive-unlock profiles are maintained in the [freemkv-unlock](https://github.com/freemkv/freemkv-unlock) repository.
|
|
|
|
## License
|
|
|
|
MIT
|