Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions examples/deep_probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,22 @@ fn main() {
th: None,
pairs: Some(audio_qualif),
};
let freeze_duration_check = CheckParameterValue {
min: Some(2000),
max: None,
num: None,
den: None,
th: None,
pairs: None,
};
let freeze_noise_check = CheckParameterValue {
min: None,
max: None,
num: None,
den: None,
th: Some(0.001),
pairs: None,
};

let mut silence_params = HashMap::new();
let mut black_params = HashMap::new();
Expand All @@ -159,6 +175,7 @@ fn main() {
let mut loudness_params = HashMap::new();
let mut dualmono_params = HashMap::new();
let mut sine_params = HashMap::new();
let mut freeze_params = HashMap::new();
silence_params.insert("duration".to_string(), duration_params);
black_params.insert("duration".to_string(), black_duration_params);
black_params.insert("picture".to_string(), black_picture_params);
Expand All @@ -175,6 +192,8 @@ fn main() {
ocr_params.insert("threshold".to_string(), ocr_check);
sine_params.insert("duration".to_string(), sine_duration_check);
sine_params.insert("pairing_list".to_string(), sine_qualif_check);
freeze_params.insert("duration".to_string(), freeze_duration_check);
freeze_params.insert("noise".to_string(), freeze_noise_check);
let check = DeepProbeCheck {
silence_detect: Some(silence_params),
black_detect: Some(black_params),
Expand All @@ -186,6 +205,7 @@ fn main() {
loudness_detect: Some(loudness_params),
dualmono_detect: Some(dualmono_params),
sine_detect: Some(sine_params),
freeze_detect: Some(freeze_params),
};
probe.process(LevelFilter::Off, check).unwrap();
let result = serde_json::to_string(&probe).unwrap();
Expand Down
56 changes: 56 additions & 0 deletions src/probe/deep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::probe::black_detect::{blackframes_init, detect_black_frames};
use crate::probe::blackfade_detect::detect_blackfade;
use crate::probe::crop_detect::{black_borders_init, detect_black_borders};
use crate::probe::dualmono_detect::{detect_dualmono, dualmono_init};
use crate::probe::freeze_detect::{detect_freeze, freeze_init};
use crate::probe::loudness_detect::{detect_loudness, loudness_init};
use crate::probe::ocr_detect::{detect_ocr, ocr_init};
use crate::probe::scene_detect::{detect_scene, scene_init};
Expand Down Expand Up @@ -112,6 +113,12 @@ pub struct SineResult {
pub end: i64,
}

#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct FreezeResult {
pub start: i64,
pub end: i64,
}

#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct StreamProbeResult {
stream_index: usize,
Expand Down Expand Up @@ -148,6 +155,8 @@ pub struct StreamProbeResult {
pub detected_black_and_silence: Option<Vec<BlackAndSilenceResult>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detected_sine: Option<Vec<SineResult>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detected_freeze: Option<Vec<FreezeResult>>,
}

#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
Expand Down Expand Up @@ -190,6 +199,7 @@ pub struct DeepProbeCheck {
pub loudness_detect: Option<HashMap<String, CheckParameterValue>>,
pub dualmono_detect: Option<HashMap<String, CheckParameterValue>>,
pub sine_detect: Option<HashMap<String, CheckParameterValue>>,
pub freeze_detect: Option<HashMap<String, CheckParameterValue>>,
}

#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -237,6 +247,7 @@ pub enum CheckName {
Loudness,
DualMono,
Tone,
Freeze,
}

impl fmt::Display for DeepProbeResult {
Expand Down Expand Up @@ -295,6 +306,11 @@ impl fmt::Display for DeepProbeResult {
"{:30} : {:?}",
"Media offline detection", stream.detected_ocr
)?;
writeln!(
f,
"{:30} : {:?}",
"Freeze detection", stream.detected_freeze
)?;
writeln!(
f,
"{:30} : {:?}",
Expand Down Expand Up @@ -341,6 +357,7 @@ impl StreamProbeResult {
detected_dualmono: None,
detected_sine: None,
detected_bitrate: None,
detected_freeze: None,
}
}
}
Expand Down Expand Up @@ -589,6 +606,14 @@ impl DeepProbe {
deep_orders.output_results.insert(CheckName::Tone, vec![]);
}

if let Some(params) = deep_orders.check.freeze_detect.clone() {
deep_orders.orders.insert(
CheckName::Freeze,
freeze_init(&self.filename, deep_orders.video_indexes.clone(), params).unwrap(),
);
deep_orders.output_results.insert(CheckName::Freeze, vec![]);
}

Ok(())
}

Expand Down Expand Up @@ -693,6 +718,17 @@ impl DeepProbe {
)
}
}
CheckName::Freeze => {
if let Some(params) = deep_orders.check.freeze_detect.clone() {
detect_freeze(
&deep_orders.output_results,
&mut deep_orders.streams,
deep_orders.video_indexes.clone(),
params,
deep_orders.video_details.clone(),
)
}
}
}
}

Expand Down Expand Up @@ -929,6 +965,22 @@ fn deep_probe() {
th: None,
pairs: Some(audio_qualif),
};
let freeze_duration_check = CheckParameterValue {
min: Some(2000),
max: None,
num: None,
den: None,
th: None,
pairs: None,
};
let freeze_noise_check = CheckParameterValue {
min: None,
max: None,
num: None,
den: None,
th: Some(0.001),
pairs: None,
};

let mut silence_params = HashMap::new();
let mut black_params = HashMap::new();
Expand All @@ -940,6 +992,7 @@ fn deep_probe() {
let mut loudness_params = HashMap::new();
let mut dualmono_params = HashMap::new();
let mut sine_params = HashMap::new();
let mut freeze_params = HashMap::new();
silence_params.insert("duration".to_string(), duration_params);
black_params.insert("duration".to_string(), black_duration_params);
black_params.insert("picture".to_string(), black_picture_params);
Expand All @@ -956,6 +1009,8 @@ fn deep_probe() {
ocr_params.insert("threshold".to_string(), ocr_check);
sine_params.insert("duration".to_string(), sine_check);
sine_params.insert("pairing_list".to_string(), sine_qualif_check);
freeze_params.insert("duration".to_string(), freeze_duration_check);
freeze_params.insert("noise".to_string(), freeze_noise_check);
let check = DeepProbeCheck {
silence_detect: Some(silence_params),
black_detect: Some(black_params),
Expand All @@ -967,6 +1022,7 @@ fn deep_probe() {
loudness_detect: Some(loudness_params),
dualmono_detect: Some(dualmono_params),
sine_detect: Some(sine_params),
freeze_detect: Some(freeze_params),
};
let id = Uuid::parse_str("ef7e3ad9-a08f-4cd0-9fec-3ac465bbdd85").unwrap();
let mut probe = DeepProbe::new("tests/test_file.mxf", id);
Expand Down
152 changes: 152 additions & 0 deletions src/probe/freeze_detect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use crate::{
order::{
filter_input::FilterInput,
filter_output::FilterOutput,
input::Input,
input_kind::InputKind,
output::Output,
output_kind::OutputKind,
stream::Stream,
Filter, Order,
OutputResult::{self, Entry},
ParameterValue,
},
probe::deep::{CheckName, CheckParameterValue, FreezeResult, StreamProbeResult, VideoDetails},
};
use std::collections::{BTreeMap, HashMap};

pub fn freeze_init(
filename: &str,
video_indexes: Vec<u32>,
params: HashMap<String, CheckParameterValue>,
) -> Result<Order, String> {
let mut order = create_graph(filename, video_indexes, params).unwrap();
if let Err(msg) = order.setup() {
error!("{:?}", msg);
}
Ok(order)
}

pub fn create_graph(
filename: &str,
video_indexes: Vec<u32>,
params: HashMap<String, CheckParameterValue>,
) -> Result<Order, String> {
let mut filters = vec![];
let mut inputs = vec![];
let mut outputs = vec![];
for i in video_indexes {
let input_identifier = format!("video_input_{i}");
let output_identifier = format!("video_output_{i}");

let input_streams = vec![Stream {
index: i,
label: Some(input_identifier.clone()),
}];

let mut freezedetect_params: HashMap<String, ParameterValue> = HashMap::new();
if let Some(duration) = params.get("duration") {
if let Some(min_duration) = duration.min {
let min = (min_duration * 1000) as f64;
freezedetect_params.insert("duration".to_string(), ParameterValue::Float(min));
}
}
if let Some(noise) = params.get("noise") {
if let Some(noise_th) = noise.th {
freezedetect_params.insert("noise".to_string(), ParameterValue::Float(noise_th));
}
}

filters.push(Filter {
name: "freezedetect".to_string(),
label: Some(format!("freezedetect_filter{i}")),
parameters: freezedetect_params.clone(),
inputs: Some(vec![FilterInput {
kind: InputKind::Stream,
stream_label: input_identifier,
}]),
outputs: Some(vec![FilterOutput {
stream_label: output_identifier.clone(),
}]),
});

inputs.push(Input::Streams {
id: i,
path: filename.to_string(),
streams: input_streams,
});
outputs.push(Output {
kind: Some(OutputKind::VideoMetadata),
keys: vec![
"lavfi.freezedetect.freeze_start".to_string(),
"lavfi.freezedetect.freeze_end".to_string(),
],
stream: Some(output_identifier),
path: None,
streams: vec![],
parameters: HashMap::new(),
});
}

Order::new(inputs, filters, outputs)
}

pub fn detect_freeze(
output_results: &BTreeMap<CheckName, Vec<OutputResult>>,
streams: &mut [StreamProbeResult],
video_indexes: Vec<u32>,
params: HashMap<String, CheckParameterValue>,
video_details: VideoDetails,
) {
for index in video_indexes {
streams[index as usize].detected_freeze = Some(vec![]);
}
let results = output_results.get(&CheckName::Freeze).unwrap();
info!("END OF FREEZE PROCESS");
info!("-> {:?} frames processed", results.len());

let end_from_duration = match video_details.stream_duration {
Some(duration) => ((duration - video_details.frame_duration) * 1000.0).round() as i64,
None => ((results.len() as f32 - 1.0) / video_details.frame_rate * 1000.0).round() as i64,
};
let mut max_duration = None;
if let Some(duration) = params.get("duration") {
max_duration = duration.max;
}

for result in results {
if let Entry(entry_map) = result {
if let Some(stream_id) = entry_map.get("stream_id") {
let index: i32 = stream_id.parse().unwrap();
if streams[(index) as usize].detected_freeze.is_none() {
error!("Error : unexpected detection on stream ${index}");
break;
}
let detected_freeze = streams[(index) as usize].detected_freeze.as_mut().unwrap();
let mut freeze = FreezeResult {
start: 0,
end: end_from_duration,
};

if let Some(value) = entry_map.get("lavfi.freezedetect.freeze_start") {
freeze.start = (value.parse::<f32>().unwrap() * 1000.0).round() as i64;
detected_freeze.push(freeze);
}
if let Some(value) = entry_map.get("lavfi.freezedetect.freeze_end") {
if let Some(last_detect) = detected_freeze.last_mut() {
last_detect.end = ((value.parse::<f32>().unwrap() - video_details.frame_duration)
* 1000.0)
.round() as i64;
let freeze_duration = last_detect.end - last_detect.start
+ (video_details.frame_duration * 1000.0).round() as i64;
if let Some(max) = max_duration {
if freeze_duration > max as i64 {
detected_freeze.pop();
}
}
}
}
}
}
}
}
1 change: 1 addition & 0 deletions src/probe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod blackfade_detect;
mod crop_detect;
pub mod deep;
mod dualmono_detect;
mod freeze_detect;
mod loudness_detect;
mod ocr_detect;
mod scene_detect;
Expand Down
10 changes: 10 additions & 0 deletions tests/deep_probe.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@
"score": 33,
"index": 2
}
],
"detected_freeze": [
{
"start": 0,
"end": 4920
},
{
"start": 9960,
"end": 14920
}
]
},
{
Expand Down
Loading