-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
919 additions
and
296 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
use env_logger::{Builder, Env}; | ||
use log::LevelFilter; | ||
use stainless_ffmpeg::probe::deep::CheckParameterValue; | ||
use stainless_ffmpeg::probe::*; | ||
use std::collections::HashMap; | ||
use std::env; | ||
|
||
fn main() { | ||
Builder::from_env(Env::default().default_filter_or("debug")).init(); | ||
|
||
if let Some(path) = env::args().last() { | ||
let mut probe = DeepProbe::new(&path); | ||
let duration_params = CheckParameterValue { | ||
min: Some(2000), | ||
max: Some(10000), | ||
num: None, | ||
den: None, | ||
}; | ||
let mut params = HashMap::new(); | ||
params.insert("duration".to_string(), duration_params); | ||
let check = DeepProbeCheck { | ||
silence_detect: params, | ||
}; | ||
probe.process(LevelFilter::Off, check).unwrap(); | ||
let result = serde_json::to_string(&probe).unwrap(); | ||
println!("{}", result); | ||
|
||
if let Some(result) = probe.result { | ||
println!("Deep probe result : \n{}", result); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
use crate::format_context::FormatContext; | ||
use crate::probe::silence_detect::detect_silence; | ||
use log::LevelFilter; | ||
use stainless_ffmpeg_sys::*; | ||
use std::{cmp, collections::HashMap, fmt}; | ||
|
||
#[derive(Debug, Deserialize, PartialEq, Serialize)] | ||
pub struct DeepProbe { | ||
#[serde(skip_serializing)] | ||
filename: String, | ||
pub result: Option<DeepProbeResult>, | ||
} | ||
|
||
#[derive(Debug, Deserialize, PartialEq, Serialize)] | ||
pub struct DeepProbeResult { | ||
#[serde(default)] | ||
streams: Vec<StreamProbeResult>, | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
pub struct SilenceResult { | ||
pub start: i64, | ||
pub end: i64, | ||
} | ||
|
||
fn is_false(x: &bool) -> bool { | ||
!x | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
pub struct StreamProbeResult { | ||
stream_index: usize, | ||
count_packets: usize, | ||
min_packet_size: i32, | ||
max_packet_size: i32, | ||
#[serde(skip_serializing_if = "Vec::is_empty")] | ||
pub detected_silence: Vec<SilenceResult>, | ||
#[serde(skip_serializing_if = "is_false")] | ||
pub silent_stream: bool, | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] | ||
pub struct CheckParameterValue { | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub min: Option<u64>, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub max: Option<u64>, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub num: Option<u64>, | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub den: Option<u64>, | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, PartialEq)] | ||
pub struct DeepProbeCheck { | ||
pub silence_detect: HashMap<String, CheckParameterValue>, | ||
} | ||
|
||
impl fmt::Display for DeepProbeResult { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
for (index, stream) in self.streams.iter().enumerate() { | ||
writeln!(f, "\n{:30} : {:?}", "Stream Index", index)?; | ||
writeln!(f, "{:30} : {:?}", "Number of packets", stream.count_packets)?; | ||
writeln!( | ||
f, | ||
"{:30} : {:?}", | ||
"Minimum packet size", stream.min_packet_size | ||
)?; | ||
writeln!( | ||
f, | ||
"{:30} : {:?}", | ||
"Maximum packet size", stream.max_packet_size | ||
)?; | ||
writeln!( | ||
f, | ||
"{:30} : {:?}", | ||
"Silence detection", stream.detected_silence | ||
)?; | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl StreamProbeResult { | ||
pub fn new() -> Self { | ||
StreamProbeResult { | ||
stream_index: 0, | ||
count_packets: 0, | ||
min_packet_size: std::i32::MAX, | ||
max_packet_size: std::i32::MIN, | ||
detected_silence: vec![], | ||
silent_stream: false, | ||
} | ||
} | ||
} | ||
|
||
impl DeepProbe { | ||
pub fn new(filename: &str) -> Self { | ||
DeepProbe { | ||
filename: filename.to_owned(), | ||
result: None, | ||
} | ||
} | ||
|
||
pub fn process(&mut self, log_level: LevelFilter, check: DeepProbeCheck) -> Result<(), String> { | ||
let av_log_level = match log_level { | ||
LevelFilter::Error => AV_LOG_ERROR, | ||
LevelFilter::Warn => AV_LOG_WARNING, | ||
LevelFilter::Info => AV_LOG_INFO, | ||
LevelFilter::Debug => AV_LOG_DEBUG, | ||
LevelFilter::Trace => AV_LOG_TRACE, | ||
LevelFilter::Off => AV_LOG_QUIET, | ||
}; | ||
|
||
unsafe { | ||
av_log_set_level(av_log_level); | ||
} | ||
|
||
let mut context = FormatContext::new(&self.filename).unwrap(); | ||
if context.open_input().is_err() { | ||
self.result = None; | ||
context.close_input(); | ||
return Ok(()); | ||
} | ||
|
||
let mut streams = vec![]; | ||
streams.resize(context.get_nb_streams() as usize, StreamProbeResult::new()); | ||
loop { | ||
match context.next_packet() { | ||
Ok(packet) => unsafe { | ||
let stream_index = (*packet.packet).stream_index as usize; | ||
let packet_size = (*packet.packet).size; | ||
|
||
streams[stream_index].stream_index = stream_index; | ||
streams[stream_index].count_packets += 1; | ||
streams[stream_index].min_packet_size = | ||
cmp::min(packet_size, streams[stream_index].min_packet_size); | ||
streams[stream_index].max_packet_size = | ||
cmp::max(packet_size, streams[stream_index].max_packet_size); | ||
}, | ||
Err(_) => { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if !check.silence_detect.is_empty() { | ||
let mut audio_indexes = vec![]; | ||
for stream_index in 0..context.get_nb_streams() { | ||
if context.get_stream_type(stream_index as isize) == AVMediaType::AVMEDIA_TYPE_AUDIO { | ||
audio_indexes.push(stream_index); | ||
} | ||
} | ||
detect_silence( | ||
&self.filename, | ||
&mut streams, | ||
audio_indexes, | ||
check.silence_detect, | ||
); | ||
} | ||
|
||
self.result = Some(DeepProbeResult { streams }); | ||
|
||
context.close_input(); | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[test] | ||
fn deep_probe_mxf_sample() { | ||
use serde_json; | ||
use std::collections::HashMap; | ||
use std::fs::File; | ||
use std::io::prelude::*; | ||
|
||
let mut probe = DeepProbe::new("tests/PAL_1080i_MPEG_XDCAM-HD_colorbar.mxf"); | ||
let mut params = HashMap::new(); | ||
let duration = CheckParameterValue { | ||
min: Some(2000), | ||
max: None, | ||
num: None, | ||
den: None, | ||
}; | ||
params.insert("duration".to_string(), duration); | ||
let check_list = DeepProbeCheck { | ||
silence_detect: params, | ||
}; | ||
probe.process(LevelFilter::Error, check_list).unwrap(); | ||
|
||
let mut file = File::open("tests/deep_probe.json").unwrap(); | ||
let mut contents = String::new(); | ||
file.read_to_string(&mut contents).unwrap(); | ||
|
||
let reference: DeepProbe = serde_json::from_str(&contents).unwrap(); | ||
assert_eq!(probe, reference); | ||
} |
Oops, something went wrong.