Add labels module: 4 disc file parsers for stream labels

src/labels/ with 4 parsers tried in order:
1. language_streams.txt (Warner CTRM CSV)
2. menu_base.prop (Warner CTRM properties)
3. streamproperties.xml + playbackconfig.xml (Criterion XML)
4. bluray_project.bin (Pixelogic binary tokens)

Disc::scan() calls labels::extract() → apply_disc_labels().
If no disc files found, streams keep MPLS data as-is.
No JAR fallback — disc files or nothing.

Covers 4/8 discs with JARs (Dunkirk UHD, V for Vendetta BD,
Being There, Barbie). Remaining 3 (Civil War, Dune, V for
Vendetta UHD) have no disc config files.
This commit is contained in:
MattJackson
2026-04-07 18:42:33 -07:00
parent 8a95787426
commit ba44f7d928
7 changed files with 714 additions and 2 deletions
+88
View File
@@ -0,0 +1,88 @@
//! Stream label extraction from BD-J disc files.
//!
//! Searches the disc UDF filesystem for known config files that contain
//! stream labels (language, purpose, codec, forced flags). Four formats
//! supported, tried in order:
//!
//! 1. `language_streams.txt` — Warner CTRM CSV format
//! 2. `menu_base.prop` — Warner CTRM properties format
//! 3. `streamproperties.xml` + `playbackconfig.xml` — Criterion XML format
//! 4. `bluray_project.bin` — Pixelogic binary format
mod language_streams;
mod menu_base;
mod stream_properties;
mod bluray_project;
use crate::drive::DriveSession;
use crate::udf::UdfFs;
/// A stream label extracted from disc config files.
#[derive(Debug, Clone)]
pub struct StreamLabel {
/// STN index (1-based)
pub stream_number: u16,
/// Audio or Subtitle
pub stream_type: StreamLabelType,
/// ISO 639-2 language code
pub language: String,
/// Display name (e.g. "AudioEnglishDolby", "English Dolby Atmos")
pub name: String,
/// Stream purpose
pub purpose: LabelPurpose,
/// Additional qualifier
pub qualifier: LabelQualifier,
/// Codec hint from config (e.g. "MLP", "AC3", "atmos")
pub codec_hint: String,
/// Regional variant (e.g. "US", "UK", "CF", "CS")
pub region: String,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum StreamLabelType {
Audio,
Subtitle,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LabelPurpose {
/// Normal dialogue track
Normal,
/// Audio commentary
Commentary,
/// Descriptive audio (visually impaired)
Descriptive,
/// Music score only
Score,
/// In-movie experience
Ime,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LabelQualifier {
None,
/// Subtitles for deaf and hard of hearing
Sdh,
/// Descriptive service
DescriptiveService,
/// Forced/narrative subtitle
Forced,
}
/// Try all parsers in order, return first successful result.
pub fn extract(session: &mut DriveSession, udf: &UdfFs) -> Vec<StreamLabel> {
// Try each format in order
if let Some(labels) = language_streams::parse(session, udf) {
return labels;
}
if let Some(labels) = menu_base::parse(session, udf) {
return labels;
}
if let Some(labels) = stream_properties::parse(session, udf) {
return labels;
}
if let Some(labels) = bluray_project::parse(session, udf) {
return labels;
}
Vec::new()
}