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}