mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-02-16 21:05:15 +00:00
closedcaption: Port to combine 4
This commit is contained in:
parent
660e325bbc
commit
8370fb8a11
5 changed files with 135 additions and 120 deletions
|
@ -9,7 +9,7 @@ repository = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||||
combine = "3.6"
|
combine = "4.0"
|
||||||
either = "1"
|
either = "1"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
|
|
@ -94,7 +94,7 @@ struct State {
|
||||||
need_flush_stop: bool,
|
need_flush_stop: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
type CombineError<'a> = combine::easy::Errors<u8, &'a [u8], combine::stream::PointerOffset>;
|
type CombineError<'a> = combine::easy::ParseError<&'a [u8]>;
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
|
@ -21,6 +21,7 @@ use combine;
|
||||||
use combine::parser::byte::hex_digit;
|
use combine::parser::byte::hex_digit;
|
||||||
use combine::parser::range::{range, take_while1};
|
use combine::parser::range::{range, take_while1};
|
||||||
use combine::parser::repeat::skip_many;
|
use combine::parser::repeat::skip_many;
|
||||||
|
use combine::parser::EasyParser;
|
||||||
use combine::{any, choice, eof, from_str, many1, one_of, optional, token, unexpected_any, value};
|
use combine::{any, choice, eof, from_str, many1, one_of, optional, token, unexpected_any, value};
|
||||||
use combine::{ParseError, Parser, RangeStream};
|
use combine::{ParseError, Parser, RangeStream};
|
||||||
|
|
||||||
|
@ -59,22 +60,20 @@ pub struct MccParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for parsing a run of ASCII, decimal digits and converting them into a `u32`
|
/// Parser for parsing a run of ASCII, decimal digits and converting them into a `u32`
|
||||||
fn digits<'a, I: 'a>() -> impl Parser<Input = I, Output = u32>
|
fn digits<'a, I: 'a>() -> impl Parser<I, Output = u32>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
from_str(take_while1(|c: u8| c >= b'0' && c <= b'9').message("while parsing digits"))
|
from_str(take_while1(|c: u8| c >= b'0' && c <= b'9').message("while parsing digits"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a run of decimal digits, that converts them into a `u32` and checks if the result is
|
/// Parser for a run of decimal digits, that converts them into a `u32` and checks if the result is
|
||||||
/// in the allowed range.
|
/// in the allowed range.
|
||||||
fn digits_range<'a, I: 'a, R: std::ops::RangeBounds<u32>>(
|
fn digits_range<'a, I: 'a, R: std::ops::RangeBounds<u32>>(range: R) -> impl Parser<I, Output = u32>
|
||||||
range: R,
|
|
||||||
) -> impl Parser<Input = I, Output = u32>
|
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
digits().then(move |v| {
|
digits().then(move |v| {
|
||||||
if range.contains(&v) {
|
if range.contains(&v) {
|
||||||
|
@ -86,10 +85,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a timecode in the form `hh:mm:ss:fs`
|
/// Parser for a timecode in the form `hh:mm:ss:fs`
|
||||||
fn timecode<'a, I: 'a>() -> impl Parser<Input = I, Output = TimeCode>
|
fn timecode<'a, I: 'a>() -> impl Parser<I, Output = TimeCode>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
digits(),
|
digits(),
|
||||||
|
@ -111,10 +110,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser that checks for EOF and optionally `\n` or `\r\n` before EOF
|
/// Parser that checks for EOF and optionally `\n` or `\r\n` before EOF
|
||||||
fn end_of_line<'a, I: 'a>() -> impl Parser<Input = I, Output = ()> + 'a
|
fn end_of_line<'a, I: 'a>() -> impl Parser<I, Output = ()> + 'a
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
optional(choice((range(b"\n".as_ref()), range(b"\r\n".as_ref())))),
|
optional(choice((range(b"\n".as_ref()), range(b"\r\n".as_ref())))),
|
||||||
|
@ -125,10 +124,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for the MCC header
|
/// Parser for the MCC header
|
||||||
fn header<'a, I: 'a>() -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn header<'a, I: 'a>() -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
range(b"File Format=MacCaption_MCC V".as_ref()),
|
range(b"File Format=MacCaption_MCC V".as_ref()),
|
||||||
|
@ -140,10 +139,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser that accepts only an empty line
|
/// Parser that accepts only an empty line
|
||||||
fn empty_line<'a, I: 'a>() -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn empty_line<'a, I: 'a>() -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
end_of_line()
|
end_of_line()
|
||||||
.map(|_| MccLine::Empty)
|
.map(|_| MccLine::Empty)
|
||||||
|
@ -152,10 +151,10 @@ where
|
||||||
|
|
||||||
/// Parser for an MCC comment, i.e. a line starting with `//`. We don't return the actual comment
|
/// Parser for an MCC comment, i.e. a line starting with `//`. We don't return the actual comment
|
||||||
/// text as it's irrelevant for us.
|
/// text as it's irrelevant for us.
|
||||||
fn comment<'a, I: 'a>() -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn comment<'a, I: 'a>() -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(token(b'/'), token(b'/'), skip_many(any()))
|
(token(b'/'), token(b'/'), skip_many(any()))
|
||||||
.map(|_| MccLine::Comment)
|
.map(|_| MccLine::Comment)
|
||||||
|
@ -163,10 +162,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for the MCC UUID line.
|
/// Parser for the MCC UUID line.
|
||||||
fn uuid<'a, I: 'a>() -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn uuid<'a, I: 'a>() -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
range(b"UUID=".as_ref()),
|
range(b"UUID=".as_ref()),
|
||||||
|
@ -178,10 +177,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for the MCC Time Code Rate line.
|
/// Parser for the MCC Time Code Rate line.
|
||||||
fn time_code_rate<'a, I: 'a>() -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn time_code_rate<'a, I: 'a>() -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
range(b"Time Code Rate=".as_ref()),
|
range(b"Time Code Rate=".as_ref()),
|
||||||
|
@ -195,10 +194,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for generic MCC metadata lines in the form `key=value`.
|
/// Parser for generic MCC metadata lines in the form `key=value`.
|
||||||
fn metadata<'a, I: 'a>() -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn metadata<'a, I: 'a>() -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
take_while1(|b| b != b'='),
|
take_while1(|b| b != b'='),
|
||||||
|
@ -215,55 +214,73 @@ where
|
||||||
///
|
///
|
||||||
/// It returns an `Either` of the single hex encoded byte or the short-cut byte sequence as a
|
/// It returns an `Either` of the single hex encoded byte or the short-cut byte sequence as a
|
||||||
/// static byte slice.
|
/// static byte slice.
|
||||||
fn mcc_payload_item<'a, I: 'a>() -> impl Parser<Input = I, Output = Either<u8, &'static [u8]>>
|
fn mcc_payload_item<'a, I: 'a>() -> impl Parser<I, Output = Either<u8, &'static [u8]>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
choice!(
|
// FIXME: Switch back to the choice! macro once https://github.com/rust-lang/rust/issues/68666
|
||||||
|
// is fixed and we depend on a new enough Rust version.
|
||||||
|
choice((
|
||||||
token(b'G').map(|_| Either::Right([0xfau8, 0x00, 0x00].as_ref())),
|
token(b'G').map(|_| Either::Right([0xfau8, 0x00, 0x00].as_ref())),
|
||||||
token(b'H').map(|_| Either::Right([0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00].as_ref())),
|
token(b'H').map(|_| Either::Right([0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00].as_ref())),
|
||||||
token(b'I').map(|_| Either::Right(
|
token(b'I').map(|_| {
|
||||||
[0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00].as_ref()
|
Either::Right([0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00].as_ref())
|
||||||
)),
|
}),
|
||||||
token(b'J').map(|_| Either::Right(
|
token(b'J').map(|_| {
|
||||||
[0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00].as_ref()
|
Either::Right(
|
||||||
)),
|
[
|
||||||
token(b'K').map(|_| Either::Right(
|
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
|
||||||
[
|
]
|
||||||
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
.as_ref(),
|
||||||
0x00, 0x00
|
)
|
||||||
]
|
}),
|
||||||
.as_ref()
|
token(b'K').map(|_| {
|
||||||
)),
|
Either::Right(
|
||||||
token(b'L').map(|_| Either::Right(
|
[
|
||||||
[
|
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
||||||
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
0x00, 0x00,
|
||||||
0x00, 0x00, 0xfa, 0x00, 0x00
|
]
|
||||||
]
|
.as_ref(),
|
||||||
.as_ref()
|
)
|
||||||
)),
|
}),
|
||||||
token(b'M').map(|_| Either::Right(
|
token(b'L').map(|_| {
|
||||||
[
|
Either::Right(
|
||||||
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
[
|
||||||
0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00
|
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
||||||
]
|
0x00, 0x00, 0xfa, 0x00, 0x00,
|
||||||
.as_ref()
|
]
|
||||||
)),
|
.as_ref(),
|
||||||
token(b'N').map(|_| Either::Right(
|
)
|
||||||
[
|
}),
|
||||||
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
token(b'M').map(|_| {
|
||||||
0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00
|
Either::Right(
|
||||||
]
|
[
|
||||||
.as_ref()
|
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
||||||
)),
|
0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
|
||||||
token(b'O').map(|_| Either::Right(
|
]
|
||||||
[
|
.as_ref(),
|
||||||
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
)
|
||||||
0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00
|
}),
|
||||||
]
|
token(b'N').map(|_| {
|
||||||
.as_ref()
|
Either::Right(
|
||||||
)),
|
[
|
||||||
|
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
||||||
|
0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00,
|
||||||
|
]
|
||||||
|
.as_ref(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
token(b'O').map(|_| {
|
||||||
|
Either::Right(
|
||||||
|
[
|
||||||
|
0xfau8, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa,
|
||||||
|
0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xfa, 0x00,
|
||||||
|
0x00,
|
||||||
|
]
|
||||||
|
.as_ref(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
token(b'P').map(|_| Either::Right([0xfbu8, 0x80, 0x80].as_ref())),
|
token(b'P').map(|_| Either::Right([0xfbu8, 0x80, 0x80].as_ref())),
|
||||||
token(b'Q').map(|_| Either::Right([0xfcu8, 0x80, 0x80].as_ref())),
|
token(b'Q').map(|_| Either::Right([0xfcu8, 0x80, 0x80].as_ref())),
|
||||||
token(b'R').map(|_| Either::Right([0xfdu8, 0x80, 0x80].as_ref())),
|
token(b'R').map(|_| Either::Right([0xfdu8, 0x80, 0x80].as_ref())),
|
||||||
|
@ -280,8 +297,8 @@ where
|
||||||
};
|
};
|
||||||
let val = (hex_to_u8(u) << 4) | hex_to_u8(l);
|
let val = (hex_to_u8(u) << 4) | hex_to_u8(l);
|
||||||
Either::Left(val)
|
Either::Left(val)
|
||||||
})
|
}),
|
||||||
)
|
))
|
||||||
.message("while parsing MCC payload")
|
.message("while parsing MCC payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,10 +328,10 @@ impl<'a> Extend<Either<u8, &'a [u8]>> for VecExtend {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for the whole MCC payload with conversion to the underlying byte values.
|
/// Parser for the whole MCC payload with conversion to the underlying byte values.
|
||||||
fn mcc_payload<'a, I: 'a>() -> impl Parser<Input = I, Output = Vec<u8>>
|
fn mcc_payload<'a, I: 'a>() -> impl Parser<I, Output = Vec<u8>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
many1(mcc_payload_item())
|
many1(mcc_payload_item())
|
||||||
.map(|v: VecExtend| v.0)
|
.map(|v: VecExtend| v.0)
|
||||||
|
@ -322,10 +339,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a MCC caption line in the form `timecode\tpayload`.
|
/// Parser for a MCC caption line in the form `timecode\tpayload`.
|
||||||
fn caption<'a, I: 'a>(parse_payload: bool) -> impl Parser<Input = I, Output = MccLine<'a>>
|
fn caption<'a, I: 'a>(parse_payload: bool) -> impl Parser<I, Output = MccLine<'a>>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
timecode(),
|
timecode(),
|
||||||
|
@ -368,8 +385,7 @@ impl MccParser {
|
||||||
&mut self,
|
&mut self,
|
||||||
line: &'a [u8],
|
line: &'a [u8],
|
||||||
parse_payload: bool,
|
parse_payload: bool,
|
||||||
) -> Result<MccLine<'a>, combine::easy::Errors<u8, &'a [u8], combine::stream::PointerOffset>>
|
) -> Result<MccLine<'a>, combine::easy::ParseError<&'a [u8]>> {
|
||||||
{
|
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Header => header()
|
State::Header => header()
|
||||||
.message("while in Header state")
|
.message("while in Header state")
|
||||||
|
|
|
@ -51,7 +51,7 @@ struct State {
|
||||||
last_timecode: Option<gst_video::ValidVideoTimeCode>,
|
last_timecode: Option<gst_video::ValidVideoTimeCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type CombineError<'a> = combine::easy::Errors<u8, &'a [u8], combine::stream::PointerOffset>;
|
type CombineError<'a> = combine::easy::ParseError<&'a [u8]>;
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
use combine;
|
use combine;
|
||||||
use combine::parser::byte::hex_digit;
|
use combine::parser::byte::hex_digit;
|
||||||
use combine::parser::range::{range, take_while1};
|
use combine::parser::range::{range, take_while1};
|
||||||
|
use combine::parser::EasyParser;
|
||||||
use combine::{choice, eof, from_str, many1, one_of, optional, token, unexpected_any, value};
|
use combine::{choice, eof, from_str, many1, one_of, optional, token, unexpected_any, value};
|
||||||
use combine::{ParseError, Parser, RangeStream};
|
use combine::{ParseError, Parser, RangeStream};
|
||||||
|
|
||||||
|
@ -51,22 +52,20 @@ pub struct SccParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for parsing a run of ASCII, decimal digits and converting them into a `u32`
|
/// Parser for parsing a run of ASCII, decimal digits and converting them into a `u32`
|
||||||
fn digits<'a, I: 'a>() -> impl Parser<Input = I, Output = u32>
|
fn digits<'a, I: 'a>() -> impl Parser<I, Output = u32>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
from_str(take_while1(|c: u8| c >= b'0' && c <= b'9').message("while parsing digits"))
|
from_str(take_while1(|c: u8| c >= b'0' && c <= b'9').message("while parsing digits"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a run of decimal digits, that converts them into a `u32` and checks if the result is
|
/// Parser for a run of decimal digits, that converts them into a `u32` and checks if the result is
|
||||||
/// in the allowed range.
|
/// in the allowed range.
|
||||||
fn digits_range<'a, I: 'a, R: std::ops::RangeBounds<u32>>(
|
fn digits_range<'a, I: 'a, R: std::ops::RangeBounds<u32>>(range: R) -> impl Parser<I, Output = u32>
|
||||||
range: R,
|
|
||||||
) -> impl Parser<Input = I, Output = u32>
|
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
digits().then(move |v| {
|
digits().then(move |v| {
|
||||||
if range.contains(&v) {
|
if range.contains(&v) {
|
||||||
|
@ -78,10 +77,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a timecode in the form `hh:mm:ss:fs`
|
/// Parser for a timecode in the form `hh:mm:ss:fs`
|
||||||
fn timecode<'a, I: 'a>() -> impl Parser<Input = I, Output = TimeCode>
|
fn timecode<'a, I: 'a>() -> impl Parser<I, Output = TimeCode>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
digits(),
|
digits(),
|
||||||
|
@ -103,10 +102,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser that checks for EOF and optionally `\n` or `\r\n` before EOF
|
/// Parser that checks for EOF and optionally `\n` or `\r\n` before EOF
|
||||||
fn end_of_line<'a, I: 'a>() -> impl Parser<Input = I, Output = ()> + 'a
|
fn end_of_line<'a, I: 'a>() -> impl Parser<I, Output = ()> + 'a
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
optional(choice((range(b"\n".as_ref()), range(b"\r\n".as_ref())))),
|
optional(choice((range(b"\n".as_ref()), range(b"\r\n".as_ref())))),
|
||||||
|
@ -117,10 +116,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for the SCC header
|
/// Parser for the SCC header
|
||||||
fn header<'a, I: 'a>() -> impl Parser<Input = I, Output = SccLine> + 'a
|
fn header<'a, I: 'a>() -> impl Parser<I, Output = SccLine> + 'a
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(range(b"Scenarist_SCC V1.0".as_ref()), end_of_line())
|
(range(b"Scenarist_SCC V1.0".as_ref()), end_of_line())
|
||||||
.map(|_| SccLine::Header)
|
.map(|_| SccLine::Header)
|
||||||
|
@ -128,10 +127,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser that accepts only an empty line
|
/// Parser that accepts only an empty line
|
||||||
fn empty_line<'a, I: 'a>() -> impl Parser<Input = I, Output = SccLine> + 'a
|
fn empty_line<'a, I: 'a>() -> impl Parser<I, Output = SccLine> + 'a
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
end_of_line()
|
end_of_line()
|
||||||
.map(|_| SccLine::Empty)
|
.map(|_| SccLine::Empty)
|
||||||
|
@ -140,10 +139,10 @@ where
|
||||||
|
|
||||||
/// A single SCC payload item. This is ASCII hex encoded bytes.
|
/// A single SCC payload item. This is ASCII hex encoded bytes.
|
||||||
/// It returns an tuple of `(u8, u8)` of the hex encoded bytes.
|
/// It returns an tuple of `(u8, u8)` of the hex encoded bytes.
|
||||||
fn scc_payload_item<'a, I: 'a>() -> impl Parser<Input = I, Output = (u8, u8)>
|
fn scc_payload_item<'a, I: 'a>() -> impl Parser<I, Output = (u8, u8)>
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
((hex_digit(), hex_digit(), hex_digit(), hex_digit()).map(|(u, l, m, n)| {
|
((hex_digit(), hex_digit(), hex_digit(), hex_digit()).map(|(u, l, m, n)| {
|
||||||
let hex_to_u8 = |v: u8| match v {
|
let hex_to_u8 = |v: u8| match v {
|
||||||
|
@ -182,10 +181,10 @@ impl Extend<(u8, u8)> for VecExtend {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for the whole SCC payload with conversion to the underlying byte values.
|
/// Parser for the whole SCC payload with conversion to the underlying byte values.
|
||||||
fn scc_payload<'a, I: 'a>() -> impl Parser<Input = I, Output = Vec<u8>> + 'a
|
fn scc_payload<'a, I: 'a>() -> impl Parser<I, Output = Vec<u8>> + 'a
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
many1(
|
many1(
|
||||||
(
|
(
|
||||||
|
@ -199,10 +198,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser for a SCC caption line in the form `timecode\tpayload`.
|
/// Parser for a SCC caption line in the form `timecode\tpayload`.
|
||||||
fn caption<'a, I: 'a>() -> impl Parser<Input = I, Output = SccLine> + 'a
|
fn caption<'a, I: 'a>() -> impl Parser<I, Output = SccLine> + 'a
|
||||||
where
|
where
|
||||||
I: RangeStream<Item = u8, Range = &'a [u8]>,
|
I: RangeStream<Token = u8, Range = &'a [u8]>,
|
||||||
I::Error: ParseError<I::Item, I::Range, I::Position>,
|
I::Error: ParseError<I::Token, I::Range, I::Position>,
|
||||||
{
|
{
|
||||||
(timecode(), token(b'\t'), scc_payload(), end_of_line())
|
(timecode(), token(b'\t'), scc_payload(), end_of_line())
|
||||||
.map(|(tc, _, value, _)| SccLine::Caption(tc, value))
|
.map(|(tc, _, value, _)| SccLine::Caption(tc, value))
|
||||||
|
@ -224,7 +223,7 @@ impl SccParser {
|
||||||
pub fn parse_line<'a>(
|
pub fn parse_line<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
line: &'a [u8],
|
line: &'a [u8],
|
||||||
) -> Result<SccLine, combine::easy::Errors<u8, &'a [u8], combine::stream::PointerOffset>> {
|
) -> Result<SccLine, combine::easy::ParseError<&'a [u8]>> {
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Header => header()
|
State::Header => header()
|
||||||
.message("while in Header state")
|
.message("while in Header state")
|
||||||
|
|
Loading…
Reference in a new issue