diff --git a/src/probe/black_and_silence.rs b/src/probe/black_and_silence.rs index d19c56e..47720b2 100644 --- a/src/probe/black_and_silence.rs +++ b/src/probe/black_and_silence.rs @@ -6,6 +6,7 @@ pub fn detect_black_and_silence( video_indexes: Vec, audio_indexes: Vec, params: HashMap, + frame_duration: f32, ) { let mut bas = BlackAndSilenceResult { start: 0, end: 0 }; let mut duration_min = None; @@ -33,7 +34,7 @@ pub fn detect_black_and_silence( bas.start = bl_detect.start; } if bas.start < bas.end { - let bas_duration: i64 = bas.end - bas.start; + let bas_duration: i64 = bas.end - bas.start + (frame_duration * 1000.0).round() as i64; let detected_black_and_silence = streams[si_index as usize] .detected_black_and_silence .as_mut() diff --git a/src/probe/black_detect.rs b/src/probe/black_detect.rs index 7102bdb..e3c1056 100644 --- a/src/probe/black_detect.rs +++ b/src/probe/black_detect.rs @@ -1,14 +1,11 @@ use crate::{ - format_context::FormatContext, order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, Filter, Order, OutputResult::Entry, ParameterValue, }, - probe::deep::{BlackResult, CheckParameterValue, StreamProbeResult}, - stream::Stream as ContextStream, + probe::deep::{BlackResult, CheckParameterValue, StreamProbeResult, VideoDetails}, }; -use ffmpeg_sys_next::AVMediaType; use std::collections::HashMap; pub fn create_graph( @@ -82,6 +79,7 @@ pub fn detect_black_frames( streams: &mut [StreamProbeResult], video_indexes: Vec, params: HashMap, + video_details: VideoDetails, ) { let mut order = create_graph(filename, video_indexes.clone(), params.clone()).unwrap(); if let Err(msg) = order.setup() { @@ -96,31 +94,17 @@ pub fn detect_black_frames( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut duration = 0; + 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; let mut min_duration = None; if let Some(duration) = params.get("duration") { max_duration = duration.max; min_duration = duration.min; } - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - let frame_rate = stream.get_frame_rate().to_float(); - if let Some(stream_duration) = stream.get_duration() { - duration = (stream_duration * 1000.0) as i64; - } else { - duration = (results.len() as f32 / frame_rate * 1000.0) as i64; - } - } - } - } + for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { @@ -132,7 +116,7 @@ pub fn detect_black_frames( let detected_black = streams[(index) as usize].detected_black.as_mut().unwrap(); let mut black = BlackResult { start: 0, - end: duration, + end: end_from_duration, }; if let Some(value) = entry_map.get("lavfi.black_start") { @@ -141,8 +125,11 @@ pub fn detect_black_frames( } if let Some(value) = entry_map.get("lavfi.black_end") { if let Some(last_detect) = detected_black.last_mut() { - last_detect.end = (value.parse::().unwrap() * 1000.0).round() as i64; - let black_duration = last_detect.end - last_detect.start; + last_detect.end = ((value.parse::().unwrap() - video_details.frame_duration) + * 1000.0) + .round() as i64; + let black_duration = last_detect.end - last_detect.start + + (video_details.frame_duration * 1000.0).round() as i64; if let Some(max) = max_duration { if black_duration > max as i64 { detected_black.pop(); diff --git a/src/probe/crop_detect.rs b/src/probe/crop_detect.rs index c997d79..aa54570 100644 --- a/src/probe/crop_detect.rs +++ b/src/probe/crop_detect.rs @@ -1,13 +1,9 @@ -use crate::format_context::FormatContext; use crate::order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, }; use crate::order::{Filter, Order, OutputResult::Entry, ParameterValue}; -use crate::probe::deep::{CheckParameterValue, CropResult, StreamProbeResult}; -use crate::stream::Stream as ContextStream; -use crate::tools::rational::Rational; -use ffmpeg_sys_next::AVMediaType; +use crate::probe::deep::{CheckParameterValue, CropResult, StreamProbeResult, VideoDetails}; use std::collections::HashMap; pub fn create_graph( @@ -91,31 +87,15 @@ pub fn detect_black_borders( streams: &mut [StreamProbeResult], video_indexes: Vec, params: HashMap, + video_details: VideoDetails, ) { - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } - - let mut nb_frames = 0; - let mut limit = 0; - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - if let Some(frames) = stream.get_nb_frames() { - nb_frames = frames; - } - // black threshold : 16 pour 8bits / 64 pour 10bits / 256 pour 12bits - limit = match stream.get_bits_per_raw_sample() { - Some(10) => 64, - Some(12) => 256, - _ => 16, - } - } - } - } + let nb_frames = video_details.stream_frames.unwrap_or(0); + // black threshold : 16 pour 8bits / 64 pour 10bits / 256 pour 12bits + let limit = match video_details.bits_raw_sample { + Some(10) => 64, + Some(12) => 256, + _ => 16, + }; let mut order = create_graph(filename, video_indexes.clone(), params, nb_frames, limit).unwrap(); if let Err(msg) = order.setup() { error!("{:?}", msg); @@ -129,27 +109,11 @@ pub fn detect_black_borders( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut time_base = 1.0; - let mut metadata_width = 0; - let mut metadata_height = 0; - let mut real_width = 0; - let mut real_height = 0; let mut w_changed = false; let mut h_changed = false; - let mut pict_size = Rational::new(1, 1); + let mut real_width = video_details.metadata_width; + let mut real_height = video_details.metadata_height; - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - time_base = stream.get_time_base().to_float(); - metadata_width = stream.get_width(); - metadata_height = stream.get_height(); - pict_size = stream.get_picture_aspect_ratio(); - real_width = metadata_width; - real_height = metadata_height; - } - } - } for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { @@ -160,8 +124,8 @@ pub fn detect_black_borders( } let detected_crop = streams[(index) as usize].detected_crop.as_mut().unwrap(); let mut crop = CropResult { - width: metadata_width, - height: metadata_height, + width: video_details.metadata_width, + height: video_details.metadata_height, ..Default::default() }; if let (Some(x1), Some(x2)) = ( @@ -169,7 +133,7 @@ pub fn detect_black_borders( entry_map.get("lavfi.cropdetect.x2"), ) { let width = x2.parse::().unwrap() - x1.parse::().unwrap() + 1; - if width != metadata_width { + if width != video_details.metadata_width { w_changed = true; } real_width = width; @@ -179,7 +143,7 @@ pub fn detect_black_borders( entry_map.get("lavfi.cropdetect.y2"), ) { let height = y2.parse::().unwrap() - y1.parse::().unwrap() + 1; - if height != metadata_height { + if height != video_details.metadata_height { h_changed = true; } real_height = height; @@ -188,9 +152,10 @@ pub fn detect_black_borders( if w_changed || h_changed { crop.width = real_width; crop.height = real_height; - crop.pts = (pts.parse::().unwrap() * time_base * 1000.0).round() as i64; - let real_aspect = - (real_width * pict_size.num) as f32 / (real_height * pict_size.den) as f32; + crop.pts = + (pts.parse::().unwrap() * video_details.time_base * 1000.0).round() as i64; + let real_aspect = (real_width * video_details.aspect_ratio.num) as f32 + / (real_height * video_details.aspect_ratio.den) as f32; crop.aspect_ratio = real_aspect; detected_crop.push(crop); w_changed = false; diff --git a/src/probe/deep.rs b/src/probe/deep.rs index 0bd7fa7..e0e4ab4 100644 --- a/src/probe/deep.rs +++ b/src/probe/deep.rs @@ -9,6 +9,7 @@ use crate::probe::scene_detect::detect_scene; use crate::probe::silence_detect::detect_silence; use crate::probe::sine_detect::detect_sine; use crate::stream::Stream; +use crate::tools::rational::Rational; use ffmpeg_sys_next::*; use log::LevelFilter; use std::{cmp, collections::HashMap, fmt}; @@ -173,6 +174,19 @@ pub struct DeepProbeCheck { pub sine_detect: Option>, } +#[derive(Clone, Debug, Default)] +pub struct VideoDetails { + pub frame_rate: f32, + pub time_base: f32, + pub frame_duration: f32, + pub stream_duration: Option, + pub stream_frames: Option, + pub bits_raw_sample: Option, + pub metadata_width: i32, + pub metadata_height: i32, + pub aspect_ratio: Rational, +} + impl fmt::Display for DeepProbeResult { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (index, stream) in self.streams.iter().enumerate() { @@ -300,6 +314,22 @@ impl Track { } } +impl VideoDetails { + pub fn new() -> Self { + VideoDetails { + frame_rate: 1.0, + time_base: 1.0, + frame_duration: 0.0, + stream_duration: None, + stream_frames: None, + bits_raw_sample: None, + metadata_width: 0, + metadata_height: 0, + aspect_ratio: Rational::new(1, 1), + } + } +} + impl DeepProbe { pub fn new(filename: &str, id: Uuid) -> Self { DeepProbe { @@ -330,6 +360,7 @@ impl DeepProbe { return Ok(()); } + let mut video_details = VideoDetails::new(); let mut streams = vec![]; streams.resize(context.get_nb_streams() as usize, StreamProbeResult::new()); while let Ok(packet) = context.next_packet() { @@ -351,6 +382,15 @@ impl DeepProbe { streams[stream_index].color_primaries = stream.get_color_primaries(); streams[stream_index].color_trc = stream.get_color_trc(); streams[stream_index].color_matrix = stream.get_color_matrix(); + video_details.frame_duration = stream.get_frame_rate().invert().to_float(); + video_details.frame_rate = stream.get_frame_rate().to_float(); + video_details.time_base = stream.get_time_base().to_float(); + video_details.stream_duration = stream.get_duration(); + video_details.stream_frames = stream.get_nb_frames(); + video_details.bits_raw_sample = stream.get_bits_per_raw_sample(); + video_details.metadata_width = stream.get_width(); + video_details.metadata_height = stream.get_height(); + video_details.aspect_ratio = stream.get_picture_aspect_ratio(); } } } @@ -373,6 +413,7 @@ impl DeepProbe { &mut streams, audio_indexes.clone(), silence_parameters, + video_details.clone(), ); } @@ -382,6 +423,7 @@ impl DeepProbe { &mut streams, video_indexes.clone(), black_parameters, + video_details.clone(), ); } @@ -392,6 +434,7 @@ impl DeepProbe { video_indexes.clone(), audio_indexes.clone(), black_and_silence_parameters, + video_details.frame_duration, ); } } @@ -402,6 +445,7 @@ impl DeepProbe { &mut streams, video_indexes.clone(), crop_parameters, + video_details.clone(), ); } @@ -411,6 +455,7 @@ impl DeepProbe { &mut streams, video_indexes.clone(), scene_parameters, + video_details.frame_rate, ); } @@ -420,6 +465,7 @@ impl DeepProbe { &mut streams, video_indexes.clone(), ocr_parameters, + video_details.clone(), ); } @@ -444,11 +490,18 @@ impl DeepProbe { &mut streams, audio_indexes.clone(), dualmono_parameters, + video_details.clone(), ); } if let Some(sine_parameters) = check.sine_detect { - detect_sine(&self.filename, &mut streams, audio_indexes, sine_parameters); + detect_sine( + &self.filename, + &mut streams, + audio_indexes, + sine_parameters, + video_details.frame_rate, + ); } let mut format = FormatProbeResult::new(); diff --git a/src/probe/dualmono_detect.rs b/src/probe/dualmono_detect.rs index 32e52da..2c2faf4 100644 --- a/src/probe/dualmono_detect.rs +++ b/src/probe/dualmono_detect.rs @@ -1,14 +1,11 @@ -use crate::format_context::FormatContext; use crate::{ order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, Filter, Order, OutputResult::Entry, ParameterValue, }, - probe::deep::{CheckParameterValue, DualMonoResult, StreamProbeResult}, - stream::Stream as ContextStream, + probe::deep::{CheckParameterValue, DualMonoResult, StreamProbeResult, VideoDetails}, }; -use ffmpeg_sys_next::AVMediaType; use std::collections::HashMap; pub fn create_graph( @@ -119,6 +116,7 @@ pub fn detect_dualmono( streams: &mut [StreamProbeResult], audio_indexes: Vec, params: HashMap, + video_details: VideoDetails, ) { let mut order = create_graph(filename, ¶ms).unwrap(); let mut max_duration = None; @@ -137,7 +135,6 @@ pub fn detect_dualmono( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut duration = 0; let mut audio_stream_qualif_number = 0; match params.get("pairing_list") { @@ -156,21 +153,10 @@ pub fn detect_dualmono( None => warn!("No input message for the dualmono analysis (list of indexes to merge)"), } - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - let frame_rate = stream.get_frame_rate().to_float() as f64; - duration = (results.len() as f64 / audio_stream_qualif_number as f64 / frame_rate - * 1000.0) as i64; - } - } - } + let end_from_duration = (((results.len() as f64 / audio_stream_qualif_number as f64) - 1.0) + / video_details.frame_rate as f64 + * 1000.0) + .round() as i64; for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { @@ -185,7 +171,7 @@ pub fn detect_dualmono( .unwrap(); let mut dualmono = DualMonoResult { start: 0, - end: duration, + end: end_from_duration, }; if let Some(value) = entry_map.get("lavfi.aphasemeter.mono_start") { dualmono.start = (value.parse::().unwrap() * 1000.0).round() as i64; @@ -193,7 +179,9 @@ pub fn detect_dualmono( } if let Some(value) = entry_map.get("lavfi.aphasemeter.mono_end") { if let Some(last_detect) = detected_dualmono.last_mut() { - last_detect.end = (value.parse::().unwrap() * 1000.0).round() as i64; + last_detect.end = + ((value.parse::().unwrap() - video_details.frame_duration as f64) * 1000.0) + .round() as i64; } } if let Some(value) = entry_map.get("lavfi.aphasemeter.mono_duration") { @@ -213,7 +201,8 @@ pub fn detect_dualmono( .as_mut() .unwrap(); if let Some(last_detect) = detected_dualmono.last() { - let duration = last_detect.end - last_detect.start; + let duration = last_detect.end - last_detect.start + + (video_details.frame_duration * 1000.0).round() as i64; if let Some(max) = max_duration { if duration > max as i64 { detected_dualmono.pop(); diff --git a/src/probe/loudness_detect.rs b/src/probe/loudness_detect.rs index 9f4e0db..460607e 100644 --- a/src/probe/loudness_detect.rs +++ b/src/probe/loudness_detect.rs @@ -1,4 +1,3 @@ -use crate::format_context::FormatContext; use crate::order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, Filter, Order, OutputResult::Entry, @@ -126,12 +125,6 @@ pub fn detect_loudness( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { diff --git a/src/probe/ocr_detect.rs b/src/probe/ocr_detect.rs index 98c7f37..1bfe23b 100644 --- a/src/probe/ocr_detect.rs +++ b/src/probe/ocr_detect.rs @@ -1,12 +1,9 @@ -use crate::format_context::FormatContext; use crate::order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, Filter, Order, OutputResult::Entry, ParameterValue, }; -use crate::probe::deep::{CheckParameterValue, OcrResult, StreamProbeResult}; -use crate::stream::Stream as ContextStream; -use ffmpeg_sys_next::AVMediaType; +use crate::probe::deep::{CheckParameterValue, OcrResult, StreamProbeResult, VideoDetails}; use std::collections::HashMap; pub fn create_graph( @@ -80,6 +77,7 @@ pub fn detect_ocr( streams: &mut [StreamProbeResult], video_indexes: Vec, params: HashMap, + video_details: VideoDetails, ) { let mut order = create_graph(filename, video_indexes.clone(), ¶ms).unwrap(); if let Err(msg) = order.setup() { @@ -94,27 +92,9 @@ pub fn detect_ocr( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut frame_rate = 1.0; let mut media_offline_detected = false; - let mut nb_frames = 0; - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - frame_rate = stream.get_frame_rate().to_float(); - if let Some(frames_number) = stream.get_nb_frames() { - nb_frames = frames_number; - } else { - nb_frames = results.len() as i64; - } - } - } - } + let last_frame = video_details.stream_frames.unwrap_or(results.len() as i64) - 1; + for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { @@ -126,7 +106,7 @@ pub fn detect_ocr( let detected_ocr = streams[(index) as usize].detected_ocr.as_mut().unwrap(); let mut ocr = OcrResult { frame_start: 0, - frame_end: nb_frames as u64, + frame_end: last_frame as u64, text: "".to_string(), word_confidence: "".to_string(), }; @@ -134,7 +114,8 @@ pub fn detect_ocr( if media_offline_detected { if let Some(last_detect) = detected_ocr.last_mut() { if let Some(value) = entry_map.get("lavfi.scd.time") { - last_detect.frame_end = (value.parse::().unwrap() * frame_rate - 1.0) as u64; + last_detect.frame_end = + (value.parse::().unwrap() * video_details.frame_rate - 1.0) as u64; media_offline_detected = false; } } @@ -144,7 +125,8 @@ pub fn detect_ocr( media_offline_detected = true; ocr.text = value.to_string(); if let Some(value) = entry_map.get("lavfi.scd.time") { - ocr.frame_start = (value.parse::().unwrap() * frame_rate) as u64; + ocr.frame_start = + (value.parse::().unwrap() * video_details.frame_rate) as u64; } if let Some(value) = entry_map.get("lavfi.ocr.confidence") { let mut word_conf = value.to_string().replace(char::is_whitespace, "%,"); diff --git a/src/probe/scene_detect.rs b/src/probe/scene_detect.rs index 10ad29f..f5701cd 100644 --- a/src/probe/scene_detect.rs +++ b/src/probe/scene_detect.rs @@ -1,12 +1,9 @@ -use crate::format_context::FormatContext; use crate::order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, Filter, Order, OutputResult::Entry, ParameterValue, }; use crate::probe::deep::{CheckParameterValue, FalseSceneResult, SceneResult, StreamProbeResult}; -use crate::stream::Stream as ContextStream; -use ffmpeg_sys_next::AVMediaType; use std::collections::HashMap; pub fn create_graph( @@ -67,6 +64,7 @@ pub fn detect_scene( streams: &mut [StreamProbeResult], video_indexes: Vec, params: HashMap, + frame_rate: f32, ) { let mut order = create_graph(filename, video_indexes.clone(), ¶ms).unwrap(); if let Err(msg) = order.setup() { @@ -82,21 +80,8 @@ pub fn detect_scene( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut frame_rate = 1.0; let mut scene_count = 0; - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - frame_rate = stream.get_frame_rate().to_float(); - } - } - } + for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { diff --git a/src/probe/silence_detect.rs b/src/probe/silence_detect.rs index b9afa72..6b4652d 100644 --- a/src/probe/silence_detect.rs +++ b/src/probe/silence_detect.rs @@ -1,12 +1,9 @@ -use crate::format_context::FormatContext; use crate::order::{ filter_input::FilterInput, filter_output::FilterOutput, input::Input, input_kind::InputKind, output::Output, output_kind::OutputKind, stream::Stream, Filter, Order, OutputResult::Entry, ParameterValue, }; -use crate::probe::deep::{CheckParameterValue, SilenceResult, StreamProbeResult}; -use crate::stream::Stream as ContextStream; -use ffmpeg_sys_next::AVMediaType; +use crate::probe::deep::{CheckParameterValue, SilenceResult, StreamProbeResult, VideoDetails}; use std::collections::HashMap; pub fn create_graph( @@ -86,6 +83,7 @@ pub fn detect_silence( streams: &mut [StreamProbeResult], audio_indexes: Vec, params: HashMap, + video_details: VideoDetails, ) { let mut order = create_graph(filename, audio_indexes.clone(), ¶ms).unwrap(); if let Err(msg) = order.setup() { @@ -100,22 +98,11 @@ pub fn detect_silence( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut duration = 0; - let mut context = FormatContext::new(filename).unwrap(); - if let Err(msg) = context.open_input() { - context.close_input(); - error!("{:?}", msg); - return; - } - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - let frame_rate = stream.get_frame_rate().to_float() as f64; - duration = (results.len() as f64 / audio_indexes.clone().len() as f64 / frame_rate - * 1000.0) as i64; - } - } - } + let end_from_duration = (((results.len() as f64 / audio_indexes.clone().len() as f64) - 1.0) + / video_details.frame_rate as f64 + * 1000.0) + .round() as i64; + let mut max_duration = None; if let Some(duration) = params.get("duration") { max_duration = duration.max; @@ -131,7 +118,7 @@ pub fn detect_silence( let detected_silence = streams[(index) as usize].detected_silence.as_mut().unwrap(); let mut silence = SilenceResult { start: 0, - end: duration, + end: end_from_duration, }; if let Some(value) = entry_map.get("lavfi.silence_start") { @@ -140,12 +127,14 @@ pub fn detect_silence( } if let Some(value) = entry_map.get("lavfi.silence_end") { if let Some(last_detect) = detected_silence.last_mut() { - last_detect.end = (value.parse::().unwrap() * 1000.0).round() as i64; + last_detect.end = + ((value.parse::().unwrap() - video_details.frame_duration as f64) * 1000.0) + .round() as i64; } } if let Some(value) = entry_map.get("lavfi.silence_duration") { if let Some(max) = max_duration { - if (value.parse::().unwrap() * 1000.0) as u64 > max { + if (value.parse::().unwrap() * 1000.0).round() as u64 > max { detected_silence.pop(); } } @@ -157,13 +146,15 @@ pub fn detect_silence( let detected_silence = streams[(index) as usize].detected_silence.as_mut().unwrap(); if detected_silence.len() == 1 && detected_silence[0].start == 0 - && detected_silence[0].end == duration + && detected_silence[0].end == end_from_duration { streams[(index) as usize].silent_stream = Some(true); } if let Some(max) = max_duration { if let Some(last_detect) = detected_silence.last() { - if (last_detect.end - last_detect.start) > max as i64 { + let silence_duration = last_detect.end - last_detect.start + + (video_details.frame_duration * 1000.0).round() as i64; + if silence_duration > max as i64 { detected_silence.pop(); } } diff --git a/src/probe/sine_detect.rs b/src/probe/sine_detect.rs index 1fb543b..09d4355 100644 --- a/src/probe/sine_detect.rs +++ b/src/probe/sine_detect.rs @@ -95,6 +95,7 @@ pub fn detect_sine( streams: &mut [StreamProbeResult], audio_indexes: Vec, params: HashMap, + frame_rate: f32, ) { let mut order = create_graph(filename, audio_indexes.clone(), ¶ms).unwrap(); if let Err(msg) = order.setup() { @@ -109,14 +110,15 @@ pub fn detect_sine( Ok(results) => { info!("END OF PROCESS"); info!("-> {:?} frames processed", results.len()); - let mut duration = 0; - let mut time_base = 1.0; + let end_from_duration = + (((results.len() as f64 / audio_indexes.len() as f64) - 1.0) / frame_rate as f64 * 1000.0) + .round() as i64; let mut tracks: Vec> = Vec::new(); let mut sine: SineResult = Default::default(); let mut range_value: f64 = 1.0; //contains the range values to code a sample let mut last_starts: HashMap> = HashMap::new(); //contains the previous declared start let mut last_crests: HashMap = HashMap::new(); //contains the crest factor from the previous frame - let mut frames: HashMap = HashMap::new(); //contains the current frame number + let mut frames: HashMap = HashMap::new(); //contains the current frame number let mut zero_cross: HashMap = HashMap::new(); //contains the number of zero crossings let mut max_duration = None; let mut min_duration = None; @@ -139,16 +141,6 @@ pub fn detect_sine( error!("{:?}", msg); return; } - for index in 0..context.get_nb_streams() { - if let Ok(stream) = ContextStream::new(context.get_stream(index as isize)) { - if let AVMediaType::AVMEDIA_TYPE_VIDEO = context.get_stream_type(index as isize) { - let frame_rate = stream.get_frame_rate().to_float() as f64; - duration = - (results.len() as f64 / audio_indexes.len() as f64 / frame_rate * 1000.0) as i64; - time_base = stream.get_time_base().to_float(); - } - } - } for result in results { if let Entry(entry_map) = result { if let Some(stream_id) = entry_map.get("stream_id") { @@ -193,9 +185,8 @@ pub fn detect_sine( let audio_stream_key = Track::new(index, channel); //update frame count - let prev_frame = frames.get(&audio_stream_key).unwrap_or(&0.0); - frames.insert(audio_stream_key.clone(), prev_frame + 1.0); - let frame = frames.get(&audio_stream_key).unwrap(); + let frame = *frames.get(&audio_stream_key).unwrap_or(&0.0); + frames.insert(audio_stream_key.clone(), frame + 1.0); let last_start_opt = last_starts.get(&audio_stream_key).unwrap_or(&None); //update signal zero crossing count @@ -213,23 +204,26 @@ pub fn detect_sine( if last_start_opt.is_some() { if let Some(last_start) = last_start_opt { //check if audio ends => 1000Hz until the end - if (frame * (time_base * 1000.0)) as i64 == duration { + if (frame / frame_rate as f64 * 1000.0).round() as i64 == end_from_duration { sine.channel = channel; sine.start = *last_start; - sine.end = duration; + sine.end = end_from_duration; //check if sine is a 1000Hz => push and reset if let Some(zero_crossing) = zero_cross.get(&audio_stream_key.clone()) { - if ((zero_crossing) / (sine.end - sine.start) as f64) == 2.0 { + let sine_duration = ((frame + 1.0) / frame_rate as f64 * 1000.0).round() + as i64 + - sine.start; + if (zero_crossing / sine_duration as f64) == 2.0 { detected_sine.push(sine); last_starts.insert(audio_stream_key.clone(), None); zero_cross.insert(audio_stream_key.clone(), 0.0); if let Some(max) = max_duration { - if (sine.end - sine.start) > max as i64 { + if sine_duration > max as i64 { detected_sine.pop(); } } if let Some(min) = min_duration { - if (sine.end - sine.start) < min as i64 { + if sine_duration < min as i64 { detected_sine.pop(); } } @@ -238,7 +232,7 @@ pub fn detect_sine( } } } else { - sine.start = ((frame - 1.0) * (time_base * 1000.0)).round() as i64; + sine.start = (frame / frame_rate as f64 * 1000.0).round() as i64; last_starts.insert(audio_stream_key.clone(), Some(sine.start)); } } else if (2_f64.sqrt() - 1e-3_f64..2_f64.sqrt() + 1e-3_f64) @@ -248,20 +242,22 @@ pub fn detect_sine( if let Some(last_start) = last_start_opt { sine.channel = channel; sine.start = *last_start; - sine.end = ((frame - 1.0) * (time_base * 1000.0)).round() as i64; + sine.end = ((frame - 1.0) / frame_rate as f64 * 1000.0).round() as i64; //check if sine is a 1000Hz => push and reset + let sine_duration = + (frame / frame_rate as f64 * 1000.0).round() as i64 - sine.start; if let Some(zero_crossing) = zero_cross.get(&audio_stream_key) { - if (zero_crossing / (sine.end - sine.start) as f64) == 2.0 { + if (zero_crossing / sine_duration as f64) == 2.0 { detected_sine.push(sine); last_starts.insert(audio_stream_key.clone(), None); zero_cross.insert(audio_stream_key.clone(), 0.0); if let Some(max) = max_duration { - if (sine.end - sine.start) > max as i64 { + if sine_duration > max as i64 { detected_sine.pop(); } } if let Some(min) = min_duration { - if (sine.end - sine.start) < min as i64 { + if sine_duration < min as i64 { detected_sine.pop(); } } diff --git a/src/tools/rational.rs b/src/tools/rational.rs index c5e5e33..a5aef24 100644 --- a/src/tools/rational.rs +++ b/src/tools/rational.rs @@ -1,7 +1,7 @@ use ffmpeg_sys_next::*; use std::mem::swap; -#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct Rational { pub num: i32, pub den: i32, diff --git a/tests/deep_probe.json b/tests/deep_probe.json index 3bda56b..2c74898 100644 --- a/tests/deep_probe.json +++ b/tests/deep_probe.json @@ -16,11 +16,11 @@ "detected_black": [ { "start": 0, - "end": 4960 + "end": 4920 }, { "start": 9960, - "end": 14960 + "end": 14920 } ], "detected_scene": [ @@ -63,15 +63,15 @@ "detected_silence": [ { "start": 3000, - "end": 6000 + "end": 5960 }, { "start": 9000, - "end": 12000 + "end": 11960 }, { "start": 15000, - "end": 18000 + "end": 17960 } ], "detected_loudness": [ @@ -88,32 +88,32 @@ "detected_black_and_silence": [ { "start": 3000, - "end": 4960 + "end": 4920 }, { "start": 9960, - "end": 12000 + "end": 11960 } ], "detected_sine": [ { "channel": 1, - "end": 3000, + "end": 2960, "start": 0 }, { "channel": 1, - "end": 9000, + "end": 8960, "start": 6000 }, { "channel": 1, - "end": 15000, + "end": 14960, "start": 12000 }, { "channel": 1, - "end": 20000, + "end": 19960, "start": 18000 } ] @@ -131,7 +131,7 @@ "detected_silence": [ { "start": 9000, - "end": 18000 + "end": 17960 } ], "detected_loudness": [ @@ -148,18 +148,18 @@ "detected_black_and_silence": [ { "start": 9960, - "end": 14960 + "end": 14920 } ], "detected_sine": [ { "channel": 1, - "end": 9000, + "end": 8960, "start": 0 }, { "channel": 1, - "end": 20000, + "end": 19960, "start": 18000 } ] @@ -219,19 +219,19 @@ "detected_dualmono": [ { "start": 0, - "end": 20000 + "end": 19960 } ], "detected_silence": [], "detected_sine": [ { "channel": 1, - "end": 20000, + "end": 19960, "start": 0 }, { "channel": 2, - "end": 20000, + "end": 19960, "start": 0 } ], @@ -263,7 +263,7 @@ "detected_sine": [ { "channel": 1, - "end": 20000, + "end": 19960, "start": 0 } ], @@ -292,14 +292,14 @@ "detected_dualmono": [ { "start": 0, - "end": 20000 + "end": 19960 } ], "detected_silence": [], "detected_sine": [ { "channel": 1, - "end": 20000, + "end": 19960, "start": 0 } ], @@ -328,14 +328,14 @@ "detected_dualmono": [ { "start": 0, - "end": 20000 + "end": 19960 } ], "detected_silence": [], "detected_sine": [ { "channel": 1, - "end": 20000, + "end": 19960, "start": 0 } ],