pub use ffcine_assembly as assembly;
pub use ffcine_audio as audio;
pub use ffcine_breakdown as breakdown;
pub use ffcine_comp as comp;
pub use ffcine_core::{ColorSpace, Error, Lut, LutType, MediaInfo, Rational, Result};
pub use ffcine_core::{anim, camera, color, geom, lut, probe};
pub use ffcine_delivery as delivery;
pub use ffcine_filters as filters;
pub use ffcine_filters::{Denoise, Grain, Spatial, Temporal};
pub use ffcine_hooks as hooks;
pub use ffcine_import as import;
pub use ffcine_ingest as ingest;
pub use ffcine_reframe as reframe;
pub use ffcine_render::{
Backend, Bake, BlendMode, Codec, ColorMapTuning, ColorOverride, Crop, Deband, Decode,
DeliveryProfile, Device, Dither, DitherMethod, EncoderSettings, GamutMapping, Grade,
HdrMetadata, Hook, Image, Layer, LayerSource, LutStage, Mask, Overlay, OverlayPart, ParamTrack,
Pipeline, PixelFormat, RateControl, RunStats, Scaler, Scaling, Size, Stage, ToneMapping, Warp,
};
pub use ffcine_render::{
backend, bake, blend, encode, extra, grade, layer, overlay, pipeline, profile, shaders,
};
pub use ffcine_stabilize as stabilize;
pub use ffcine_text as text;
pub use ffcine_timeline as timeline;
pub use ffcine_triage as triage;
#[cfg(feature = "nvof")]
pub fn stabilize_pipeline(
backend: &dyn Backend,
pipeline: &mut Pipeline,
params: &stabilize::StabilizeParams,
motion: &stabilize::MotionOptions,
cache: bool,
) -> Result<(stabilize::Stabilization, stabilize::MotionDetection)> {
let start = pipeline.start.as_secs_f64();
let (rate, frames) = match (pipeline.frame_rate, pipeline.frames) {
(Some(r), Some(n)) => (r, n),
(r, n) => {
let info = backend.probe(&pipeline.input)?;
let rate = r
.or_else(|| info.video().and_then(|(_, v)| v.frame_rate))
.ok_or_else(|| Error::Pipeline("stabilize: source has no frame rate".into()))?;
let n = n.unwrap_or_else(|| {
let left = info.duration.map_or(0.0, |d| d.as_secs_f64()) - start;
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let n = (left.max(0.0) * rate.as_f64()).round() as u64;
n
});
(rate, n)
}
};
let range = stabilize::SourceRange {
start,
frames: usize::try_from(frames).unwrap_or(usize::MAX),
rate,
};
let detect = stabilize::DetectParams::default();
let det = stabilize::detect_motion(&pipeline.input, &range, &detect, motion, cache)?;
let st = stabilize::stabilize(&det.detection, params);
let warp = Some(Warp {
transforms: st.transforms.clone(),
});
if let Some(Stage::Grade(g)) = pipeline.stages.first_mut() {
g.warp = warp;
} else {
pipeline.stages.insert(
0,
Stage::Grade(Grade {
warp,
..Grade::default()
}),
);
}
Ok((st, det))
}
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
struct ReadmeDoctests;