diff options
author | Mathieu Duponchelle <mathieu@centricular.com> | 2021-02-12 04:07:32 +0300 |
---|---|---|
committer | GStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org> | 2021-02-15 22:25:18 +0300 |
commit | 3c982a3de0bd350e586f87b8e50567552dd868f1 (patch) | |
tree | 472d42ed21f051c8fd1f75c4ff4b22d410f4857c | |
parent | 19611f0ebe84ff813f1779c80f256739449fa81f (diff) |
ccdetect: extract CDP parser to a separate module
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/474>
-rw-r--r-- | video/closedcaption/src/ccdetect/imp.rs | 138 | ||||
-rw-r--r-- | video/closedcaption/src/ccutils.rs | 152 | ||||
-rw-r--r-- | video/closedcaption/src/lib.rs | 1 |
3 files changed, 157 insertions, 134 deletions
diff --git a/video/closedcaption/src/ccdetect/imp.rs b/video/closedcaption/src/ccdetect/imp.rs index deaa430b2..c19b537c1 100644 --- a/video/closedcaption/src/ccdetect/imp.rs +++ b/video/closedcaption/src/ccdetect/imp.rs @@ -22,11 +22,9 @@ use gst::subclass::prelude::*; use gst::{gst_trace, gst_warning}; use gst_base::subclass::prelude::*; -use byteorder::{BigEndian, ByteOrder}; - +use crate::ccutils::{extract_cdp, ParseError, ParseErrorCode}; use once_cell::sync::Lazy; -use std::fmt; use std::sync::Mutex; use std::u64; @@ -83,29 +81,6 @@ struct CCPacketContents { cc708: bool, } -#[allow(clippy::enum_variant_names)] -#[derive(Debug, Clone, Copy)] -enum ParseErrorCode { - WrongLength, - WrongMagicSequence, - WrongLayout, -} - -#[derive(Debug, Clone)] -struct ParseError { - code: ParseErrorCode, - byte: usize, - msg: String, -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?} at byte {}: {}", self.code, self.byte, self.msg) - } -} - -impl std::error::Error for ParseError {} - impl CCDetect { fn detect_cc_data(data: &[u8]) -> Result<CCPacketContents, ParseError> { if data.len() % 3 != 0 { @@ -172,115 +147,10 @@ impl CCDetect { }) } - fn detect_cdp(mut data: &[u8]) -> Result<CCPacketContents, ParseError> { - /* logic from ccconverter */ - let data_len = data.len(); - - if data.len() < 11 { - return Err(ParseError { - code: ParseErrorCode::WrongLength, - byte: data_len - data.len(), - msg: format!( - "cdp packet too short {}. expected at least {}", - data.len(), - 11 - ), - }); - } - - if 0x9669 != BigEndian::read_u16(&data[..2]) { - return Err(ParseError { - code: ParseErrorCode::WrongMagicSequence, - byte: data_len - data.len(), - msg: String::from("cdp packet does not have initial magic bytes of 0x9669"), - }); - } - data = &data[2..]; - - if (data[0] as usize) != data_len { - return Err(ParseError { - code: ParseErrorCode::WrongLength, - byte: data_len - data.len(), - msg: format!( - "advertised cdp packet length {} does not match length of data {}", - data[0], data_len - ), - }); - } - data = &data[1..]; - - /* skip framerate value */ - data = &data[1..]; - - let flags = data[0]; - data = &data[1..]; - - if flags & 0x40 == 0 { - /* no cc_data */ - return Ok(CCPacketContents { - cc608: false, - cc708: false, - }); - } - - /* skip sequence counter */ - data = &data[2..]; - - /* timecode present? */ - if flags & 0x80 == 0x80 { - if data.len() < 5 { - return Err(ParseError { - code: ParseErrorCode::WrongLength, - byte: data_len - data.len(), - msg: String::from("cdp packet signals a timecode but is not large enough to contain a timecode") - }); - } - data = &data[5..]; - } - - /* cc_data */ - if data.len() < 2 { - return Err(ParseError { - code: ParseErrorCode::WrongLength, - byte: data_len - data.len(), - msg: String::from( - "cdp packet signals cc_data but is not large enough to contain cc_data", - ), - }); - } - - if data[0] != 0x72 { - return Err(ParseError { - code: ParseErrorCode::WrongMagicSequence, - byte: data_len - data.len(), - msg: String::from("ccp is missing start code 0x72"), - }); - } - data = &data[1..]; - - let cc_count = data[0]; - data = &data[1..]; - if cc_count & 0xe0 != 0xe0 { - return Err(ParseError { - code: ParseErrorCode::WrongMagicSequence, - byte: data_len - data.len(), - msg: format!("reserved bits are not 0xe0, found {:02x}", cc_count & 0xe0), - }); - } - let cc_count = cc_count & 0x1f; - let len = 3 * cc_count as usize; - - if len > data.len() { - return Err(ParseError { - code: ParseErrorCode::WrongLength, - byte: data_len - data.len(), - msg: String::from("cc_data length extends past the end of the cdp packet"), - }); - } - - /* TODO: validate checksum */ + fn detect_cdp(data: &[u8]) -> Result<CCPacketContents, ParseError> { + let data = extract_cdp(data)?; - Self::detect_cc_data(&data[..len]) + Self::detect_cc_data(data) } fn detect(format: CCFormat, data: &[u8]) -> Result<CCPacketContents, ParseError> { diff --git a/video/closedcaption/src/ccutils.rs b/video/closedcaption/src/ccutils.rs new file mode 100644 index 000000000..8d7fdadfd --- /dev/null +++ b/video/closedcaption/src/ccutils.rs @@ -0,0 +1,152 @@ +// Copyright (C) 2020 Matthew Waters <matthew@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 byteorder::{BigEndian, ByteOrder}; +use std::fmt; + +#[allow(clippy::enum_variant_names)] +#[derive(Debug, Clone, Copy)] +pub enum ParseErrorCode { + WrongLength, + WrongMagicSequence, + WrongLayout, +} + +#[derive(Debug, Clone)] +pub struct ParseError { + pub code: ParseErrorCode, + pub byte: usize, + pub msg: String, +} + +pub fn extract_cdp(mut data: &[u8]) -> Result<&[u8], ParseError> { + /* logic from ccconverter */ + let data_len = data.len(); + + if data.len() < 11 { + return Err(ParseError { + code: ParseErrorCode::WrongLength, + byte: data_len - data.len(), + msg: format!( + "cdp packet too short {}. expected at least {}", + data.len(), + 11 + ), + }); + } + + if 0x9669 != BigEndian::read_u16(&data[..2]) { + return Err(ParseError { + code: ParseErrorCode::WrongMagicSequence, + byte: data_len - data.len(), + msg: String::from("cdp packet does not have initial magic bytes of 0x9669"), + }); + } + data = &data[2..]; + + if (data[0] as usize) != data_len { + return Err(ParseError { + code: ParseErrorCode::WrongLength, + byte: data_len - data.len(), + msg: format!( + "advertised cdp packet length {} does not match length of data {}", + data[0], data_len + ), + }); + } + data = &data[1..]; + + /* skip framerate value */ + data = &data[1..]; + + let flags = data[0]; + data = &data[1..]; + + if flags & 0x40 == 0 { + /* no cc_data */ + return Ok(&[]); + } + + /* skip sequence counter */ + data = &data[2..]; + + /* timecode present? */ + if flags & 0x80 == 0x80 { + if data.len() < 5 { + return Err(ParseError { + code: ParseErrorCode::WrongLength, + byte: data_len - data.len(), + msg: String::from( + "cdp packet signals a timecode but is not large enough to contain a timecode", + ), + }); + } + data = &data[5..]; + } + + /* cc_data */ + if data.len() < 2 { + return Err(ParseError { + code: ParseErrorCode::WrongLength, + byte: data_len - data.len(), + msg: String::from( + "cdp packet signals cc_data but is not large enough to contain cc_data", + ), + }); + } + + if data[0] != 0x72 { + return Err(ParseError { + code: ParseErrorCode::WrongMagicSequence, + byte: data_len - data.len(), + msg: String::from("ccp is missing start code 0x72"), + }); + } + data = &data[1..]; + + let cc_count = data[0]; + data = &data[1..]; + if cc_count & 0xe0 != 0xe0 { + return Err(ParseError { + code: ParseErrorCode::WrongMagicSequence, + byte: data_len - data.len(), + msg: format!("reserved bits are not 0xe0, found {:02x}", cc_count & 0xe0), + }); + } + let cc_count = cc_count & 0x1f; + let len = 3 * cc_count as usize; + + if len > data.len() { + return Err(ParseError { + code: ParseErrorCode::WrongLength, + byte: data_len - data.len(), + msg: String::from("cc_data length extends past the end of the cdp packet"), + }); + } + + /* TODO: validate checksum */ + + Ok(&data[..len]) +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?} at byte {}: {}", self.code, self.byte, self.msg) + } +} + +impl std::error::Error for ParseError {} diff --git a/video/closedcaption/src/lib.rs b/video/closedcaption/src/lib.rs index 84fa5b7ac..30b8e74ed 100644 --- a/video/closedcaption/src/lib.rs +++ b/video/closedcaption/src/lib.rs @@ -24,6 +24,7 @@ mod ffi; mod caption_frame; mod ccdetect; +mod ccutils; mod cea608overlay; mod cea608tott; mod line_reader; |