1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use crate::time::{TimePoint, TimeSpan};
use std::io::{BufRead, Seek};
use super::{
ods::{self, ObjectDefinitionSegment},
pds,
pgs_image::RleEncodedImage,
segment::{read_header, skip_segment, SegmentTypeCode},
PgsError,
};
/// Trait of `Presentation Graphic Stream` decoding.
pub trait PgsDecoder {
/// Type of the Output data for the image.
type Output;
/// Parse next subtitle `PGS` and return an `Output` value.
/// The `Output` depending of the data we want to decode.
///
/// # Errors
/// Return the error happened during parsing or decoding.
fn parse_next<R>(reader: &mut R) -> Result<Option<Self::Output>, PgsError>
where
R: BufRead + Seek;
}
/// Decoder for `PGS` who provide only the times of subtitles.
pub struct DecodeTimeOnly;
impl PgsDecoder for DecodeTimeOnly {
type Output = TimeSpan;
fn parse_next<R>(reader: &mut R) -> Result<Option<Self::Output>, PgsError>
where
R: BufRead + Seek,
{
let mut start_time = None;
let mut subtitle = None;
while let Some(seg_header) = {
if subtitle.is_some() {
None
} else {
read_header(reader)?
}
} {
match seg_header.type_code() {
SegmentTypeCode::End => {
let time = TimePoint::from_msecs(i64::from(seg_header.presentation_time()));
if let Some(start_time) = start_time {
subtitle = Some(TimeSpan::new(start_time, time));
} else {
start_time = Some(time);
}
}
SegmentTypeCode::Pds
| SegmentTypeCode::Ods
| SegmentTypeCode::Pcs
| SegmentTypeCode::Wds => {
// Segment content are not taken into account, skipped
skip_segment(reader, &seg_header)?;
}
}
}
Ok(subtitle)
}
}
/// Decoder for `PGS` who provide the times and images of the subtitles.
pub struct DecodeTimeImage {}
impl PgsDecoder for DecodeTimeImage {
type Output = (TimeSpan, RleEncodedImage);
fn parse_next<R>(reader: &mut R) -> Result<Option<Self::Output>, PgsError>
where
R: BufRead + Seek,
{
let mut start_time = None;
let mut subtitle = None;
let mut palette = None;
let mut image = None;
let mut prev_ods = None;
while let Some(seg_header) = {
if subtitle.is_some() {
None
} else {
read_header(reader)?
}
} {
match seg_header.type_code() {
SegmentTypeCode::Pds => {
let seg_size = seg_header.size() as usize;
let pds = pds::read(reader, seg_size)?;
palette = Some(pds.palette);
}
SegmentTypeCode::Ods => {
let seg_size = seg_header.size() as usize;
let ods = ods::read(reader, seg_size, prev_ods.take())?;
// If data are complete, construct `image` from palette and image data
// otherwise, keep read data to complete it with data from following segment.
if let ObjectDefinitionSegment::Complete(ods) = ods {
let palette = palette.take().ok_or(PgsError::MissingPalette)?;
image = Some(RleEncodedImage::new(
ods.width,
ods.height,
palette,
ods.object_data,
));
} else {
prev_ods = Some(ods);
}
}
SegmentTypeCode::End => {
let time = TimePoint::from_msecs(i64::from(seg_header.presentation_time()));
if let Some(start_time) = start_time {
let times = TimeSpan::new(start_time, time);
let image = image.take().ok_or(PgsError::MissingImage)?;
subtitle = Some((times, image));
} else {
start_time = Some(time);
}
}
SegmentTypeCode::Pcs | SegmentTypeCode::Wds => {
// Segment not taken into account are skipped
skip_segment(reader, &seg_header)?;
}
}
}
assert!(palette.is_none()); // palette should be transferred into image before get out of the function.
assert!(prev_ods.is_none()); // Ods data should be converted into image before get out of the function.
Ok(subtitle)
}
}