Update README: remove hard numbers, add AACS and disc scanning
- Removed specific drive counts (was "206 bundled") - Removed version-specific install instructions - Added Disc::scan() + ContentReader as primary API example - Added AACS section explaining transparent decryption - Added docs/ link for technical documentation - Added E7xxx AACS error range - Evergreen — no dates or counts that need manual maintenance
This commit is contained in:
@@ -1,13 +1,12 @@
|
|||||||
[](https://crates.io/crates/libfreemkv)
|
[](https://crates.io/crates/libfreemkv)
|
||||||
[](https://docs.rs/libfreemkv)
|
[](https://docs.rs/libfreemkv)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[]()
|
|
||||||
|
|
||||||
# libfreemkv
|
# libfreemkv
|
||||||
|
|
||||||
Rust library for 4K UHD / Blu-ray / DVD optical drives. Drive access, disc format parsing, and raw sector reading in one crate. 206 bundled drive profiles.
|
Rust library for 4K UHD / Blu-ray optical drives. Drive access, disc scanning, AACS decryption, and content reading in one crate. Bundled drive profiles — no external files needed.
|
||||||
|
|
||||||
**[API Documentation](https://docs.rs/libfreemkv)**
|
**[API Documentation](https://docs.rs/libfreemkv)** · **[Technical Docs](docs/)**
|
||||||
|
|
||||||
Part of the [freemkv](https://github.com/freemkv) project.
|
Part of the [freemkv](https://github.com/freemkv) project.
|
||||||
|
|
||||||
@@ -15,101 +14,74 @@ Part of the [freemkv](https://github.com/freemkv) project.
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libfreemkv = "0.2"
|
libfreemkv = "0.3"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use libfreemkv::DriveSession;
|
use libfreemkv::{DriveSession, Disc, ScanOptions};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
// Open drive — profiles are bundled, auto-identified
|
||||||
let mut session = DriveSession::open(Path::new("/dev/sr0"))?;
|
let mut session = DriveSession::open(Path::new("/dev/sr0"))?;
|
||||||
|
|
||||||
session.unlock()?; // activate raw read mode
|
// Scan disc — UDF, playlists, streams, AACS (all automatic)
|
||||||
session.calibrate()?; // optimize read speed
|
let disc = Disc::scan(&mut session, &ScanOptions::default())?;
|
||||||
|
|
||||||
let mut buf = vec![0u8; 2048];
|
for title in &disc.titles {
|
||||||
let n = session.read_sectors(0, 1, &mut buf)?;
|
println!("{} — {} streams", title.duration_display(), title.streams.len());
|
||||||
```
|
}
|
||||||
|
|
||||||
## How It Works
|
// Read content (decrypted transparently if AACS keys available)
|
||||||
|
let mut reader = disc.open_title(&mut session, 0)?;
|
||||||
1. **INQUIRY** (SPC-4 §6.4) — reads vendor_id, product_id, product_revision, vendor_specific
|
while let Some(unit) = reader.read_unit()? {
|
||||||
2. **GET CONFIGURATION 010C** (MMC-6 §5.3.10) — reads firmware_date
|
// 6144 bytes of content per aligned unit
|
||||||
3. **Profile match** — five fields uniquely identify the drive against 206 bundled profiles
|
|
||||||
4. **READ BUFFER** — single command with per-drive mode/buffer_id activates raw read mode
|
|
||||||
5. **Signature verify** — drive responds with 4-byte signature + "MMkv" confirmation
|
|
||||||
|
|
||||||
No fingerprints. No encrypted lookups. All identification uses standard SCSI fields.
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let mut session = DriveSession::open(device_path)?;
|
|
||||||
|
|
||||||
// Drive identity
|
|
||||||
session.drive_id.vendor_id // "HL-DT-ST"
|
|
||||||
session.drive_id.product_id // "BD-RE BU40N"
|
|
||||||
session.drive_id.product_revision // "1.03"
|
|
||||||
session.drive_id.vendor_specific // "NM00000"
|
|
||||||
session.drive_id.firmware_date // "211810241934"
|
|
||||||
|
|
||||||
// Profile data
|
|
||||||
session.profile.chipset // Chipset::MediaTek
|
|
||||||
session.profile.unlock_mode // 0x01
|
|
||||||
session.profile.unlock_buf_id // 0x44
|
|
||||||
session.profile.signature // [0x99, 0x9e, 0xc3, 0x75]
|
|
||||||
|
|
||||||
// Operations
|
|
||||||
session.unlock()?;
|
|
||||||
session.calibrate()?;
|
|
||||||
session.read_sectors(lba, count, &mut buf)?;
|
|
||||||
session.status()?;
|
|
||||||
session.read_config()?;
|
|
||||||
session.read_register(index)?;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Chipset Support
|
|
||||||
|
|
||||||
| Chipset | Status | Drives | Brands |
|
|
||||||
|---------|--------|--------|--------|
|
|
||||||
| MediaTek MT1959 | Supported | 206 | LG, ASUS, HP |
|
|
||||||
| Renesas | Planned | -- | Pioneer |
|
|
||||||
|
|
||||||
## Drive Profile
|
|
||||||
|
|
||||||
Each bundled profile (compiled into the binary):
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"vendor_id": "HL-DT-ST",
|
|
||||||
"product_id": "BD-RE BU40N ",
|
|
||||||
"product_revision": "1.03",
|
|
||||||
"vendor_specific": "NM00000",
|
|
||||||
"firmware_date": "211810241934",
|
|
||||||
"chipset": "mediatek",
|
|
||||||
"unlock_mode": 1,
|
|
||||||
"unlock_buf_id": 68,
|
|
||||||
"signature": "999ec375",
|
|
||||||
"register_offsets": ["10e291", "11ab1c"]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
- **Drive access** — open, identify, unlock for raw reads
|
||||||
|
- **Disc scanning** — UDF 2.50 filesystem, MPLS playlists, CLPI clip info, BD-J labels
|
||||||
|
- **AACS decryption** — transparent key resolution and content decrypt (1.0 + 2.0)
|
||||||
|
- **Content reading** — sector reads with automatic decryption
|
||||||
|
|
||||||
|
AACS decryption requires a KEYDB.cfg file. If available at `~/.config/aacs/KEYDB.cfg` or passed via `ScanOptions`, the library handles everything — handshake, key derivation, and per-sector decryption — without the application needing to know anything about encryption.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```text
|
||||||
|
DriveSession — open, identify, unlock, read sectors
|
||||||
|
├── ScsiTransport — SG_IO (Linux), IOKit (macOS planned)
|
||||||
|
├── DriveProfile — per-drive unlock parameters (bundled)
|
||||||
|
└── Platform — MediaTek (supported), Renesas (planned)
|
||||||
|
|
||||||
|
Disc — scan titles, streams, AACS 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
|
||||||
|
├── JAR parser — BD-J audio track labels
|
||||||
|
└── AACS — key resolution + content decryption
|
||||||
|
```
|
||||||
|
|
||||||
|
See [docs/](docs/) for detailed technical documentation on each module.
|
||||||
|
|
||||||
## Error Codes
|
## Error Codes
|
||||||
|
|
||||||
| Code | Error | Meaning |
|
All errors are structured with numeric codes. No user-facing English text — applications format their own messages.
|
||||||
|------|-------|---------|
|
|
||||||
| E1000 | DeviceNotFound | Device path doesn't exist |
|
|
||||||
| E1001 | DevicePermission | No access (try sudo or cdrom group) |
|
|
||||||
| E2000 | UnsupportedDrive | No matching profile |
|
|
||||||
| E3000 | UnlockFailed | Unlock command rejected |
|
|
||||||
| E3001 | SignatureMismatch | Response signature wrong |
|
|
||||||
| E3002 | NotUnlocked | Operation requires unlock first |
|
|
||||||
| E4000 | ScsiError | SCSI command failed |
|
|
||||||
| E5000 | IoError | System I/O error |
|
|
||||||
|
|
||||||
## Platform
|
| 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 |
|
||||||
|
|
||||||
|
## Platform Support
|
||||||
|
|
||||||
| Platform | Status | Backend |
|
| Platform | Status | Backend |
|
||||||
|----------|--------|---------|
|
|----------|--------|---------|
|
||||||
@@ -117,11 +89,9 @@ Each bundled profile (compiled into the binary):
|
|||||||
| macOS | Planned | IOKit |
|
| macOS | Planned | IOKit |
|
||||||
| Windows | Planned | SPTI |
|
| Windows | Planned | SPTI |
|
||||||
|
|
||||||
The `ScsiTransport` trait abstracts the platform. Adding a backend is one file behind a `cfg` gate.
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Run `freemkv info --share` with the [freemkv CLI](https://github.com/freemkv/freemkv) to submit your drive's profile.
|
Run `freemkv info --share` with the [freemkv CLI](https://github.com/freemkv/freemkv) to contribute your drive's profile.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user