use crate::error::{Error, Result};
use crate::drive::DriveSession;
use crate::udf;
use crate::mpls;
use crate::clpi;
#[derive(Debug)]
pub struct Disc {
pub capacity_sectors: u32,
pub titles: Vec<Title>,
}
#[derive(Debug, Clone)]
pub struct Title {
pub playlist: String,
pub playlist_id: u16,
pub duration_secs: f64,
pub size_bytes: u64,
pub clip_count: usize,
pub streams: Vec<Stream>,
pub extents: Vec<Extent>,
}
#[derive(Debug, Clone)]
pub struct Stream {
pub kind: StreamKind,
pub pid: u16,
pub codec: Codec,
pub language: String,
pub resolution: String,
pub frame_rate: String,
pub channels: String,
pub sample_rate: String,
pub hdr: HdrFormat,
pub color_space: ColorSpace,
pub secondary: bool,
pub label: String,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum StreamKind {
Video,
Audio,
Subtitle,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Codec {
Hevc,
H264,
Vc1,
Mpeg2,
TrueHd,
DtsHdMa,
DtsHdHr,
Dts,
Ac3,
Ac3Plus,
Lpcm,
Pgs,
Unknown(u8),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum HdrFormat {
Sdr,
Hdr10,
DolbyVision,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ColorSpace {
Bt709,
Bt2020,
Unknown,
}
#[derive(Debug, Clone, Copy)]
pub struct Extent {
pub start_lba: u32,
pub sector_count: u32,
}
impl Codec {
pub fn name(&self) -> &'static str {
match self {
Codec::Hevc => "HEVC",
Codec::H264 => "H.264",
Codec::Vc1 => "VC-1",
Codec::Mpeg2 => "MPEG-2",
Codec::TrueHd => "TrueHD",
Codec::DtsHdMa => "DTS-HD MA",
Codec::DtsHdHr => "DTS-HD HR",
Codec::Dts => "DTS",
Codec::Ac3 => "AC-3",
Codec::Ac3Plus => "AC-3+",
Codec::Lpcm => "LPCM",
Codec::Pgs => "PGS",
Codec::Unknown(_) => "Unknown",
}
}
fn from_coding_type(ct: u8) -> Self {
match ct {
0x24 => Codec::Hevc,
0x1B => Codec::H264,
0xEA => Codec::Vc1,
0x02 => Codec::Mpeg2,
0x83 => Codec::TrueHd,
0x86 => Codec::DtsHdMa,
0x85 => Codec::DtsHdHr,
0x82 => Codec::Dts,
0x81 => Codec::Ac3,
0x84 | 0xA1 => Codec::Ac3Plus,
0x80 => Codec::Lpcm,
0xA2 => Codec::DtsHdHr,
0x90 | 0x91 => Codec::Pgs,
ct => Codec::Unknown(ct),
}
}
}
impl HdrFormat {
pub fn name(&self) -> &'static str {
match self {
HdrFormat::Sdr => "SDR",
HdrFormat::Hdr10 => "HDR10",
HdrFormat::DolbyVision => "Dolby Vision",
}
}
}
impl ColorSpace {
pub fn name(&self) -> &'static str {
match self {
ColorSpace::Bt709 => "BT.709",
ColorSpace::Bt2020 => "BT.2020",
ColorSpace::Unknown => "",
}
}
}
impl Title {
pub fn duration_display(&self) -> String {
let hrs = (self.duration_secs / 3600.0) as u32;
let mins = ((self.duration_secs % 3600.0) / 60.0) as u32;
format!("{}h {:02}m", hrs, mins)
}
pub fn size_gb(&self) -> f64 {
self.size_bytes as f64 / (1024.0 * 1024.0 * 1024.0)
}
pub fn total_sectors(&self) -> u64 {
self.extents.iter().map(|e| e.sector_count as u64).sum()
}
}
impl Stream {
pub fn display(&self) -> String {
match self.kind {
StreamKind::Video => {
let mut parts = vec![self.codec.name().to_string()];
if !self.resolution.is_empty() { parts.push(self.resolution.clone()); }
if !self.frame_rate.is_empty() { parts.push(format!("{}fps", self.frame_rate)); }
if self.hdr != HdrFormat::Sdr { parts.push(self.hdr.name().to_string()); }
if self.color_space != ColorSpace::Unknown && self.color_space != ColorSpace::Bt709 {
parts.push(self.color_space.name().to_string());
}
if self.secondary { parts.push(format!("[{}]", self.label)); }
parts.join(" ")
}
StreamKind::Audio => {
let mut parts = vec![self.codec.name().to_string()];
if !self.channels.is_empty() { parts.push(self.channels.clone()); }
if !self.sample_rate.is_empty() { parts.push(self.sample_rate.clone()); }
if !self.language.is_empty() { parts.push(format!("({})", self.language)); }
if self.secondary { parts.push("[secondary]".to_string()); }
parts.join(" ")
}
StreamKind::Subtitle => {
let mut parts = vec![self.codec.name().to_string()];
if !self.language.is_empty() { parts.push(format!("({})", self.language)); }
parts.join(" ")
}
}
}
pub fn kind_name(&self) -> &'static str {
match self.kind {
StreamKind::Video => "Video",
StreamKind::Audio => "Audio",
StreamKind::Subtitle => "Subtitle",
}
}
}
impl Disc {
pub fn capacity_gb(&self) -> f64 {
self.capacity_sectors as f64 * 2048.0 / (1024.0 * 1024.0 * 1024.0)
}
}