pgs_parse/
pgs_ods_segment.rs

1//! # PGS Object Definition Segment (ODS)
2//!
3//! This module defines the `PgsOdsSegment` struct, which represents the Object Definition Segment (ODS) 
4//! in the Presentation Graphic Stream (PGS) format. The ODS contains the object data for a subtitle, 
5//! such as the image itself, along with metadata like width, height, and sequence information.
6
7use std::rc::Rc;
8
9use crate::{pgs_memory_buffer::{BigEndian, ReadBytes}, Error, PgsMemoryBuffer, PgsSegmentHeader, Result};
10
11/// Enum representing the sequence flag in an ODS.
12/// The sequence flag indicates whether this segment is part of a sequence, and if it is, 
13/// whether it is the first, last, or both.
14#[derive(Debug, Clone, Copy, PartialEq, Hash)]
15pub enum PgsOdsSequenceFlag {
16    Unknown,
17    First,
18    Last,
19    Both,
20}
21
22impl From<u8> for PgsOdsSequenceFlag {
23    /// Converts a raw `u8` value to the corresponding `PgsOdsSequenceFlag` enum variant.
24    ///
25    /// # Parameters
26    /// - `value`: The raw `u8` value representing the sequence flag.
27    ///
28    /// # Returns
29    /// The corresponding `PgsOdsSequenceFlag` variant.    
30    fn from(value: u8) -> Self {
31        match value {
32            0x40 => PgsOdsSequenceFlag::Last,
33            0x80 => PgsOdsSequenceFlag::First,
34            0xC0 => PgsOdsSequenceFlag::Both,
35            _ => PgsOdsSequenceFlag::Unknown
36        }
37    }
38}
39
40/// Struct representing an Object Definition Segment (ODS) in a PGS file.
41/// The ODS contains the actual image data (subtitle graphics) along with metadata.
42#[derive(Debug)]
43pub struct PgsOdsSegment {
44    pub header: PgsSegmentHeader,
45    pub object_id: u16,
46    pub object_version_number: u8,
47    pub last_in_sequence_flag: PgsOdsSequenceFlag,
48    pub object_data_length: u32,
49    pub width: u16,
50    pub height: u16,
51    pub object_data: Vec<u8>
52}
53
54impl PgsOdsSegment {
55    /// Creates a new, empty `PgsOdsSegment` with the given header.
56    ///
57    /// # Parameters
58    /// - `header`: The segment header for the ODS.
59    ///
60    /// # Returns
61    /// A new `PgsOdsSegment` instance with default values for the object data.
62    fn new(header: PgsSegmentHeader) -> Self {
63        PgsOdsSegment {
64            header,
65            object_id: 0,
66            object_version_number: 0,
67            last_in_sequence_flag: PgsOdsSequenceFlag::Unknown,
68            object_data_length: 0,
69            width: 0,
70            height: 0,
71            object_data: Vec::new()
72        }
73    }
74
75    /// Constructs a `PgsOdsSegment` from the given header and raw data buffer.
76    ///
77    /// This method parses the ODS segment data, extracting the object ID, version number, sequence flag,
78    /// object data length, and optionally the object width and height (if this is the first or both sequence flag).
79    ///
80    /// # Parameters
81    /// - `header`: The segment header.
82    /// - `data`: A slice of raw data representing the contents of the ODS segment.
83    ///
84    /// # Errors
85    /// Returns `Error::InvalidSegmentDataLength` if the length of the provided data is less than the expected length.
86    ///
87    /// # Returns
88    /// An `Rc<PgsOdsSegment>` containing the parsed segment.
89    pub fn from_data(header: PgsSegmentHeader, data: &[u8]) -> Result<Rc<PgsOdsSegment>> {
90        if data.len() < header.segment_length as usize {
91            return Err(Error::InvalidSegmentDataLength);
92        }
93
94        let mut segment = PgsOdsSegment::new(header);
95
96        let mut buffer: PgsMemoryBuffer = PgsMemoryBuffer::from(data);
97        segment.object_id = buffer.read_u16::<BigEndian>()?;
98        segment.object_version_number = buffer.read_u8()?;
99        segment.last_in_sequence_flag = PgsOdsSequenceFlag::from(buffer.read_u8()?);
100
101        // Length have different of 4 bytes because w/h
102        segment.object_data_length = buffer.read_u24::<BigEndian>()? - 4;
103
104        let (width, height) = if segment.last_in_sequence_flag == PgsOdsSequenceFlag::First || segment.last_in_sequence_flag == PgsOdsSequenceFlag::Both {
105            let width = buffer.read_u16::<BigEndian>()?;
106            let height = buffer.read_u16::<BigEndian>()?;
107            (width, height)
108        } else {
109            (0, 0)
110        };
111
112        segment.width = width;
113        segment.height = height;
114        segment.object_data = buffer.read_into_vec(segment.object_data_length)?;
115
116        Ok(Rc::new(segment))
117    }
118}