closedcaption: Move common parsers into a separate file

This commit is contained in:
Sebastian Dröge 2020-11-05 17:29:28 +02:00
parent ffae72cb0f
commit 0ff11b2cc1
4 changed files with 94 additions and 73 deletions

View file

@ -40,6 +40,7 @@ mod cea608tott;
mod line_reader;
mod mcc_enc;
mod mcc_parse;
mod parser_utils;
mod scc_enc;
mod scc_parse;
mod tttocea608;

View file

@ -0,0 +1,90 @@
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.
use nom::IResult;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TimeCode {
pub hours: u32,
pub minutes: u32,
pub seconds: u32,
pub frames: u32,
pub drop_frame: bool,
}
/// Parser for parsing a run of ASCII, decimal digits and converting them into a `u32`
pub fn digits(s: &[u8]) -> IResult<&[u8], u32> {
use nom::bytes::complete::take_while;
use nom::character::is_digit;
use nom::combinator::map_res;
map_res(
map_res(take_while(is_digit), |s: &[u8]| std::str::from_utf8(s)),
|s: &str| s.parse::<u32>(),
)(s)
}
/// Parser for a run of decimal digits, that converts them into a `u32` and checks if the result is
/// in the allowed range.
pub fn digits_range<R: std::ops::RangeBounds<u32>>(
range: R,
) -> impl FnMut(&[u8]) -> IResult<&[u8], u32> {
use nom::combinator::verify;
use nom::error::context;
move |s: &[u8]| context("digits out of range", verify(digits, |v| range.contains(v)))(s)
}
/// Parser for a timecode in the form `hh:mm:ss:fs`
pub fn timecode(s: &[u8]) -> IResult<&[u8], TimeCode> {
use nom::character::complete::{char, one_of};
use nom::combinator::map;
use nom::error::context;
use nom::sequence::tuple;
context(
"invalid timecode",
map(
tuple((
digits,
char(':'),
digits_range(0..60),
char(':'),
digits_range(0..60),
one_of(":.;,"),
digits,
)),
|(hours, _, minutes, _, seconds, sep, frames)| TimeCode {
hours,
minutes,
seconds,
frames,
drop_frame: sep == ';' || sep == ',',
},
),
)(s)
}
/// Parser that checks for EOF and optionally `\n` or `\r\n` before EOF
pub fn end_of_line(s: &[u8]) -> IResult<&[u8], ()> {
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::combinator::{eof, map, opt};
use nom::sequence::pair;
map(pair(opt(alt((tag("\r\n"), tag("\n")))), eof), |_| ())(s)
}

View file

@ -23,8 +23,9 @@ use gst::subclass::prelude::*;
use std::sync::{Mutex, MutexGuard};
use super::parser::{SccLine, SccParser, TimeCode};
use super::parser::{SccLine, SccParser};
use crate::line_reader::LineReader;
use crate::parser_utils::TimeCode;
lazy_static! {
static ref CAT: gst::DebugCategory = {

View file

@ -16,17 +16,9 @@
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.
use crate::parser_utils::{end_of_line, timecode, TimeCode};
use nom::IResult;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TimeCode {
pub hours: u32,
pub minutes: u32,
pub seconds: u32,
pub frames: u32,
pub drop_frame: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SccLine {
Header,
@ -46,69 +38,6 @@ pub struct SccParser {
state: State,
}
/// Parser for parsing a run of ASCII, decimal digits and converting them into a `u32`
fn digits(s: &[u8]) -> IResult<&[u8], u32> {
use nom::bytes::complete::take_while;
use nom::character::is_digit;
use nom::combinator::map_res;
map_res(
map_res(take_while(is_digit), |s: &[u8]| std::str::from_utf8(s)),
|s: &str| s.parse::<u32>(),
)(s)
}
/// Parser for a run of decimal digits, that converts them into a `u32` and checks if the result is
/// in the allowed range.
fn digits_range<R: std::ops::RangeBounds<u32>>(
range: R,
) -> impl FnMut(&[u8]) -> IResult<&[u8], u32> {
use nom::combinator::verify;
use nom::error::context;
move |s: &[u8]| context("digits out of range", verify(digits, |v| range.contains(v)))(s)
}
/// Parser for a timecode in the form `hh:mm:ss:fs`
fn timecode(s: &[u8]) -> IResult<&[u8], TimeCode> {
use nom::character::complete::{char, one_of};
use nom::combinator::map;
use nom::error::context;
use nom::sequence::tuple;
context(
"invalid timecode",
map(
tuple((
digits,
char(':'),
digits_range(0..60),
char(':'),
digits_range(0..60),
one_of(":.;,"),
digits,
)),
|(hours, _, minutes, _, seconds, sep, frames)| TimeCode {
hours,
minutes,
seconds,
frames,
drop_frame: sep == ';' || sep == ',',
},
),
)(s)
}
/// Parser that checks for EOF and optionally `\n` or `\r\n` before EOF
fn end_of_line(s: &[u8]) -> IResult<&[u8], ()> {
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::combinator::{eof, map, opt};
use nom::sequence::pair;
map(pair(opt(alt((tag("\r\n"), tag("\n")))), eof), |_| ())(s)
}
/// Parser for the SCC header
fn header(s: &[u8]) -> IResult<&[u8], SccLine> {
use nom::bytes::complete::tag;