From 2b0fff8a9e11aebce06e4ed60b1ec490d55aff89 Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Thu, 30 May 2024 17:18:54 +0200 Subject: [PATCH] remove Subtitle struct, use tuple of time span and image instead --- src/vobsub/mod.rs | 19 ++++---- src/vobsub/sub.rs | 117 ++++++++-------------------------------------- 2 files changed, 29 insertions(+), 107 deletions(-) diff --git a/src/vobsub/mod.rs b/src/vobsub/mod.rs index ec8b9ed..7d2ad07 100644 --- a/src/vobsub/mod.rs +++ b/src/vobsub/mod.rs @@ -8,18 +8,17 @@ //! extern crate image; //! extern crate subtile; //! -//! use crate::subtile::image::ImageArea; +//! use crate::subtile::image::{ImageSize, ImageArea}; //! //! let idx = subtile::vobsub::Index::open("./fixtures/example.idx").unwrap(); //! for sub in idx.subtitles() { -//! let sub = sub.unwrap(); -//! println!("Time: {:0.3}-{:0.3}", sub.start_time(), sub.end_time()); -//! println!("Always show: {:?}", sub.force()); -//! let raw_img = sub.raw_image(); -//! let area = raw_img.area(); +//! let (time_span, image) = sub.unwrap(); +//! println!("Time: {:0.3}-{:0.3}", time_span.start, time_span.end); +//! //println!("Always show: {:?}", sub.force()); +//! let area = image.area(); //! println!("At: {}, {}", area.left(), area.top()); -//! println!("Size: {}x{}", area.width(), area.height()); -//! let img: image::RgbaImage = raw_img.to_image(idx.palette()); +//! println!("Size: {}x{}", image.width(), image.height()); +//! let img: image::RgbaImage = image.to_image(idx.palette()); //! //! // You can save or manipulate `img` using the APIs provided by the Rust //! // `image` crate. @@ -72,10 +71,10 @@ mod sub; pub use self::{ idx::{read_palette, Index}, - img::VobSubIndexedImage, + img::{VobSubIndexedImage, VobSubOcrImage}, palette::{palette, Palette}, probe::{is_idx_file, is_sub_file}, - sub::{ErrorMissing, Subtitle}, + sub::ErrorMissing, }; use crate::content::ContentError; diff --git a/src/vobsub/sub.rs b/src/vobsub/sub.rs index c50f190..deede20 100644 --- a/src/vobsub/sub.rs +++ b/src/vobsub/sub.rs @@ -7,6 +7,7 @@ use super::{img::VobSubIndexedImage, mpeg2::ps, VobSubError}; use crate::{ content::{Area, AreaValues}, + time::{TimePoint, TimeSpan}, util::BytesFormatter, vobsub::{ img::{VobSubRleImage, VobSubRleImageData}, @@ -27,17 +28,9 @@ use nom::{ sequence::{preceded, Tuple}, IResult, }; -use std::{ - cmp::Ordering, - fmt::{self, Debug}, -}; +use std::{cmp::Ordering, fmt::Debug}; use thiserror::Error; -/// The default time between two adjacent subtitles if no end time is -/// provided. This is chosen to be a value that's usually representable in -/// `SRT` format, barring rounding errors. -const DEFAULT_SUBTITLE_SPACING: f64 = 0.001; - /// The default length of a subtitle if no end time is provided and no /// subtitle follows immediately after. const DEFAULT_SUBTITLE_LENGTH: f64 = 5.0; @@ -172,77 +165,6 @@ fn control_sequence(input: &[u8]) -> IResult<&[u8], ControlSequence> { )) } -/// A single subtitle. -#[derive(Clone, PartialEq)] -pub struct Subtitle { - /// Start time of subtitle, in seconds. - start_time: f64, - /// End time of subtitle, in seconds. This may be missing from certain - /// subtitles. - end_time: Option, - /// Should this subtitle be shown even when subtitles are off? - force: bool, - /// decompressed `VobSub` image data. - image: VobSubIndexedImage, -} - -impl Subtitle { - /// Start time of subtitle, in seconds. - #[must_use] - pub const fn start_time(&self) -> f64 { - self.start_time - } - - /// End time of subtitle, in seconds. This may be missing from certain - /// subtitles. - /// # Panics - /// Will panic if `end_time` is not set. As it should be set before returning subtitle. - /// If happened `end_time` is called to soon, or a change has broken the intended operation. - #[must_use] - pub fn end_time(&self) -> f64 { - self.end_time - .expect("end time should have been set before returning subtitle") - } - - /// Should this subtitle be shown even when subtitles are off? - #[must_use] - pub const fn force(&self) -> bool { - self.force - } - - /// Our decompressed image, stored with 2 bits per byte in row-major - /// order, that can be used as indices into `palette` and `alpha`. - #[must_use] - pub const fn raw_image(&self) -> &VobSubIndexedImage { - &self.image - } - - /// Set end time of subtitle if missing - pub fn sub_fix_end_time(&mut self, next: Option) { - if self.end_time.is_none() { - self.end_time = match next { - Some(next) => { - let new_end = next.start_time - DEFAULT_SUBTITLE_SPACING; - let alt_end = self.start_time + DEFAULT_SUBTITLE_LENGTH; - Some(new_end.min(alt_end)) - } - None => Some(self.start_time + DEFAULT_SUBTITLE_LENGTH), - } - } - } -} - -impl fmt::Debug for Subtitle { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("Subtitle") - .field("start_time", &self.start_time) - .field("end_time", &self.end_time) - .field("force", &self.force) - .field("image", &self.image) - .finish_non_exhaustive() - } -} - /// Parse a single `u16` value from a buffer. We don't use `nom` for this /// because it has an inconvenient error type. fn parse_be_u16_as_usize(buff: &[u8]) -> Result<(&[u8], usize), VobSubError> { @@ -265,21 +187,22 @@ trait SubDecoder<'a> { } //struct VobSubFullDecoder; -impl<'a> SubDecoder<'a> for Subtitle { +impl<'a> SubDecoder<'a> for (TimeSpan, VobSubIndexedImage) { type Output = Self; fn from_data( start_time: f64, end_time: Option, - force: bool, + _force: bool, rle_image: VobSubRleImage<'a>, ) -> Self::Output { - Self { - start_time, - end_time, - force, - image: VobSubIndexedImage::from(rle_image), - } + ( + TimeSpan::new( + TimePoint::from_secs(start_time), + TimePoint::from_secs(end_time.unwrap_or(DEFAULT_SUBTITLE_LENGTH)), + ), + VobSubIndexedImage::from(rle_image), + ) } } @@ -510,13 +433,13 @@ impl<'a> VobsubParser<'a> { } impl<'a> Iterator for VobsubParser<'a> { - type Item = Result; + type Item = Result<(TimeSpan, VobSubIndexedImage), VobSubError>; fn next(&mut self) -> Option { profiling::scope!("VobsubParser next"); let (base_time, sub_packet) = try_iter!(self.next_sub_packet()); - let subtitle = subtitle::(&sub_packet, base_time); + let subtitle = subtitle::<(TimeSpan, VobSubIndexedImage), _>(&sub_packet, base_time); // Parse our subtitle buffer. Some(subtitle) @@ -604,12 +527,12 @@ mod tests { let mut buffer = vec![]; f.read_to_end(&mut buffer).unwrap(); let mut subs = VobsubParser::new(&buffer); - let sub1 = subs.next().expect("missing sub 1").unwrap(); - assert!(sub1.start_time - 49.4 < 0.1); - assert!(sub1.end_time.unwrap() - 50.9 < 0.1); - assert!(!sub1.force); + let (time_span, img) = subs.next().expect("missing sub 1").unwrap(); + assert!(time_span.start.to_secs() - 49.4 < 0.1); + assert!(time_span.end.to_secs() - 50.9 < 0.1); + //assert!(!sub1.force); assert_eq!( - sub1.image.area(), + img.area(), Area::try_from(AreaValues { x1: 750, y1: 916, @@ -618,8 +541,8 @@ mod tests { }) .unwrap() ); - assert_eq!(*sub1.image.palette(), [0, 1, 3, 0]); - assert_eq!(*sub1.image.alpha(), [0, 15, 15, 15]); + assert_eq!(*img.palette(), [0, 1, 3, 0]); + assert_eq!(*img.alpha(), [0, 15, 15, 15]); subs.next().expect("missing sub 2").unwrap(); assert!(subs.next().is_none()); }