use gst::glib;
use crate::constants::{CDG_COMMAND, CDG_MASK, CDG_PACKET_PERIOD, CDG_PACKET_SIZE};
use gst::{Caps, TypeFind, TypeFindProbability};
use std::cmp;
const NB_WINDOWS: u64 = 8;
const TYPEFIND_SEARCH_WINDOW_SEC: i64 = 4;
const TYPEFIND_SEARCH_WINDOW: i64 =
TYPEFIND_SEARCH_WINDOW_SEC * (CDG_PACKET_SIZE as i64 * CDG_PACKET_PERIOD as i64);
fn cdg_packets_ratio(typefind: &mut TypeFind, start: i64, len: i64) -> i64 {
let mut count = 0;
let total = len / CDG_PACKET_SIZE as i64;
for offset in (start..len).step_by(CDG_PACKET_SIZE as usize) {
match typefind.peek(offset, CDG_PACKET_SIZE as u32) {
Some(data) => {
if data[0] & CDG_MASK == CDG_COMMAND {
count += 1;
}
}
None => break,
}
}
if total == 0 {
0
} else {
(count * 100) / total
}
}
fn compute_probability(typefind: &mut TypeFind) -> TypeFindProbability {
let mut best = TypeFindProbability::None;
let len = typefind
.length()
.unwrap_or(TYPEFIND_SEARCH_WINDOW as u64 * NB_WINDOWS);
let step = len / NB_WINDOWS;
let search_window = cmp::min(len as i64, TYPEFIND_SEARCH_WINDOW);
if step == 0 {
return TypeFindProbability::None;
}
for offset in (0..len).step_by(step as usize) {
let proba = match cdg_packets_ratio(typefind, offset as i64, search_window) {
0..=5 => TypeFindProbability::None,
6..=10 => TypeFindProbability::Possible,
_ => TypeFindProbability::Likely,
};
if proba == TypeFindProbability::Likely {
return proba;
}
best = cmp::max(best, proba);
}
best
}
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
TypeFind::register(
Some(plugin),
"cdg_typefind",
gst::Rank::NONE,
Some("cdg"),
Some(&Caps::builder("video/x-cdg").build()),
|typefind| {
let proba = compute_probability(typefind);
if proba != gst::TypeFindProbability::None {
typefind.suggest(proba, &Caps::builder("video/x-cdg").build());
}
},
)
}