2019-05-01 11:09:16 +00:00
|
|
|
// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate glib;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate gstreamer as gst;
|
2020-04-24 10:55:01 +00:00
|
|
|
extern crate gstreamer_base as gst_base;
|
|
|
|
extern crate gstreamer_video as gst_video;
|
2019-10-31 22:34:21 +00:00
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
2019-05-01 11:09:16 +00:00
|
|
|
|
|
|
|
mod cdgdec;
|
2019-05-26 14:12:16 +00:00
|
|
|
mod cdgparse;
|
2019-05-26 12:48:33 +00:00
|
|
|
mod constants;
|
2019-05-01 11:09:16 +00:00
|
|
|
|
2019-11-03 13:42:51 +00:00
|
|
|
use constants::{CDG_COMMAND, CDG_MASK, CDG_PACKET_PERIOD, CDG_PACKET_SIZE};
|
2019-11-03 13:50:21 +00:00
|
|
|
use gst::{Caps, TypeFind, TypeFindProbability};
|
2019-11-03 14:08:30 +00:00
|
|
|
use std::cmp;
|
2019-06-05 05:19:27 +00:00
|
|
|
|
2019-11-03 14:08:30 +00:00
|
|
|
const NB_WINDOWS: u64 = 8;
|
|
|
|
const TYPEFIND_SEARCH_WINDOW_SEC: i64 = 4;
|
2019-11-03 13:42:51 +00:00
|
|
|
const TYPEFIND_SEARCH_WINDOW: i64 =
|
|
|
|
TYPEFIND_SEARCH_WINDOW_SEC * (CDG_PACKET_SIZE as i64 * CDG_PACKET_PERIOD as i64); /* in bytes */
|
2019-06-05 05:19:27 +00:00
|
|
|
|
|
|
|
/* Return the percentage of CDG packets in the first @len bytes of @typefind */
|
2019-11-03 14:08:30 +00:00
|
|
|
fn cdg_packets_ratio(typefind: &mut TypeFind, start: i64, len: i64) -> i64 {
|
2019-06-05 05:19:27 +00:00
|
|
|
let mut count = 0;
|
|
|
|
let total = len / CDG_PACKET_SIZE as i64;
|
|
|
|
|
|
|
|
for offset in (0..len).step_by(CDG_PACKET_SIZE as usize) {
|
2019-11-03 14:08:30 +00:00
|
|
|
match typefind.peek(start + offset, CDG_PACKET_SIZE as u32) {
|
2019-06-05 05:19:27 +00:00
|
|
|
Some(data) => {
|
|
|
|
if data[0] & CDG_MASK == CDG_COMMAND {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(count * 100) / total
|
|
|
|
}
|
|
|
|
|
2019-11-03 14:08:30 +00:00
|
|
|
/* Some CDG files starts drawing right away and then pause for a while
|
|
|
|
* (typically because of the song intro) while other wait for a few
|
|
|
|
* seconds before starting to draw.
|
|
|
|
* In order to support all variants, scan through all the file per block
|
|
|
|
* of size TYPEFIND_SEARCH_WINDOW and keep the highest ratio of CDG packets
|
|
|
|
* detected. */
|
2019-11-03 13:50:21 +00:00
|
|
|
fn compute_probability(typefind: &mut TypeFind) -> TypeFindProbability {
|
2019-11-03 14:08:30 +00:00
|
|
|
let mut best = TypeFindProbability::None;
|
|
|
|
// Try looking at the start of the file if its length isn't available
|
|
|
|
let len = typefind
|
|
|
|
.get_length()
|
|
|
|
.unwrap_or(TYPEFIND_SEARCH_WINDOW as u64 * NB_WINDOWS);
|
|
|
|
let step = len / NB_WINDOWS;
|
|
|
|
|
|
|
|
for offset in (0..len).step_by(step as usize) {
|
|
|
|
let proba = match cdg_packets_ratio(typefind, offset as i64, TYPEFIND_SEARCH_WINDOW) {
|
|
|
|
0..=5 => TypeFindProbability::None,
|
|
|
|
6..=10 => TypeFindProbability::Possible,
|
|
|
|
_ => TypeFindProbability::Likely,
|
|
|
|
};
|
|
|
|
|
|
|
|
if proba == TypeFindProbability::Likely {
|
|
|
|
return proba;
|
|
|
|
}
|
|
|
|
|
|
|
|
best = cmp::max(best, proba);
|
2019-11-03 13:50:21 +00:00
|
|
|
}
|
2019-11-03 14:08:30 +00:00
|
|
|
|
|
|
|
best
|
2019-11-03 13:50:21 +00:00
|
|
|
}
|
2019-06-05 05:19:27 +00:00
|
|
|
|
2019-11-03 13:50:21 +00:00
|
|
|
fn typefind_register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
2019-06-05 05:19:27 +00:00
|
|
|
TypeFind::register(
|
|
|
|
Some(plugin),
|
|
|
|
"cdg_typefind",
|
|
|
|
gst::Rank::None,
|
|
|
|
Some("cdg"),
|
|
|
|
Some(&Caps::new_simple("video/x-cdg", &[])),
|
|
|
|
|mut typefind| {
|
2019-11-03 13:50:21 +00:00
|
|
|
let proba = compute_probability(&mut typefind);
|
2019-06-05 05:19:27 +00:00
|
|
|
|
|
|
|
if proba != gst::TypeFindProbability::None {
|
|
|
|
typefind.suggest(proba, &Caps::new_simple("video/x-cdg", &[]));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-05-01 11:09:16 +00:00
|
|
|
fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
2019-05-26 14:12:16 +00:00
|
|
|
cdgdec::register(plugin)?;
|
|
|
|
cdgparse::register(plugin)?;
|
2019-06-05 05:19:27 +00:00
|
|
|
typefind_register(plugin)?;
|
2019-05-26 14:12:16 +00:00
|
|
|
Ok(())
|
2019-05-01 11:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gst_plugin_define!(
|
2019-05-29 06:10:08 +00:00
|
|
|
cdg,
|
2019-06-03 10:53:58 +00:00
|
|
|
env!("CARGO_PKG_DESCRIPTION"),
|
2019-05-01 11:09:16 +00:00
|
|
|
plugin_init,
|
2019-06-03 10:53:58 +00:00
|
|
|
concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
|
2019-05-01 11:09:16 +00:00
|
|
|
"MIT/X11",
|
2019-06-03 10:53:58 +00:00
|
|
|
env!("CARGO_PKG_NAME"),
|
|
|
|
env!("CARGO_PKG_NAME"),
|
|
|
|
env!("CARGO_PKG_REPOSITORY"),
|
|
|
|
env!("BUILD_REL_DATE")
|
2019-05-01 11:09:16 +00:00
|
|
|
);
|