mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-23 02:26:35 +00:00
closedcaption: Move common parsers into a separate file
This commit is contained in:
parent
ffae72cb0f
commit
0ff11b2cc1
4 changed files with 94 additions and 73 deletions
|
@ -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;
|
||||
|
|
90
video/closedcaption/src/parser_utils.rs
Normal file
90
video/closedcaption/src/parser_utils.rs
Normal 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)
|
||||
}
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue