### Previewer usage example Source: https://docs.rs/fframes/latest/fframes/struct.Previewer.html Example usage of Previewer to render a frame and save it as a PNG image. ```rust let mut previewer = fframes::Previewer::new(&video, &options)?; let mut renderer = fframes::CpuFrameRenderer::default(); let frame = previewer.timeline().resolve_frame("Intro@1.5s")?; previewer.render(frame, &mut renderer)?.save_png("intro.png")?; ``` -------------------------------- ### Result::ok example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::ok, converting Ok to Some and Err to None. ```rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); let x: Result = Err("Nothing here"); assert_eq!(x.ok(), None); ``` -------------------------------- ### animate_runtime example Source: https://docs.rs/fframes/latest/fframes/struct.Frame.html Example for animate_runtime, showing how to create a Frame, prepare an easing function, and call animate_runtime with dynamic values. ```rust use fframes::{animation, AnimationRuntime, AnimateRuntimeInput, Frame}; let frame = Frame { index: 0, global_index: 0, fps: 60, ..Default::default() }; let runtime = AnimationRuntime::from_easing(&animation::Easing::Linear(2.0)); let value = frame.animate_runtime(AnimateRuntimeInput { on: 3.2, from: 1000., to: 2000., animation_runtime: &runtime }); assert_eq!(value, 1000.); ``` -------------------------------- ### is_ok() examples Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Returns true if the result is Ok. The examples test with Ok and Err values. ```rust let x: Result = Ok(-3); assert_eq!(x.is_ok(), true); let x: Result = Err("Some error message"); assert_eq!(x.is_ok(), false); ``` -------------------------------- ### Result::as_ref example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::as_ref, producing a Result with references into the original. ```rust let x: Result = Ok(2); assert_eq!(x.as_ref(), Ok(&2)); let x: Result = Err("Error"); assert_eq!(x.as_ref(), Err(&"Error")); ``` -------------------------------- ### animate with timeline! example Source: https://docs.rs/fframes/latest/fframes/struct.Frame.html Example for the animate method using the timeline! macro with two transitions and spring easing. ```rust use crate::fframes::{ Frame, svgr, Svgr, animation::Easing}; let frame = fframes::Frame { index: 0, global_index: 0, fps: 60, ..Default::default() }; fframes::svgr!( 770., Easing::Spring { mass: 1.85, stiffness: 130.0, damping: 16.0 }, on 4.8, val 770. => 1400., Easing::Spring { mass: 1.85, stiffness: 130.0, damping: 16.0 } ))} /> ); ``` -------------------------------- ### Color usage example (Rust) Source: https://docs.rs/fframes/latest/fframes/struct.Color.html Example usage: creating colors with hex and rgba, and using them in an svgr! macro. Demonstrates const usage. ```rust use crate::fframes::{Color, Svgr, svgr}; const WHITE: Color = Color::hex("#FFFFFF"); const SEMI_TRANSPARENT_RED: Color = Color::rgba(255, 0, 0, 128); svgr!(); ``` -------------------------------- ### expect recommended message style example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Shows the recommended message style for `expect`, describing the reason the `Result` should be `Ok`. The example reads an environment variable and uses a message that focuses on the word "should". ```rust let path = std::env::var("IMPORTANT_PATH") .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); ``` -------------------------------- ### log_media_processing_start Source: https://docs.rs/fframes/latest/fframes/struct.LinesLogger.html Logs the start of media processing for a file. ```APIDOC ## log_media_processing_start ### Description Logs the start of media processing. ### Signature fn log_media_processing_start(&self, filename: &str, path: &Path) ### Parameters - **filename** (&str) - Required - The name of the media file. - **path** (&Path) - Required - The path to the media file. ``` -------------------------------- ### FFramesLogger::log_media_processing_start Source: https://docs.rs/fframes/latest/fframes/fframes_logger/struct.LinesLogger.html Logs the start of media processing for a given filename and path. ```APIDOC ## FFramesLogger::log_media_processing_start ### Description Logs the start of media processing for a given filename and path. ### Method Trait method ### Signature fn log_media_processing_start(&self, filename: &str, path: &Path) ### Parameters - **filename** (&str) - Required - The name of the media file. - **path** (&Path) - Required - The path to the media file. ``` -------------------------------- ### Create a CLI runner with fframes::cli::new Source: https://docs.rs/fframes/latest/fframes/cli/index.html Use this as the entry point for a video binary with the `cli` feature. It prepares media, builds a video, and runs the command line with default render options. The `cli::new` call returns a `Runner` whose `.run()` method returns an `ExitCode`. ```rust fn main() -> std::process::ExitCode { let media = MyMedia::prepare().unwrap(); let video = MyVideo { media: &media }; fframes::cli::new(&video, RenderOptions { media: Some(&media), ..Default::default() }).run() } ``` -------------------------------- ### write_header function with faststart support Source: https://docs.rs/fframes/latest/src/fframes/renderer/encoder.rs.html Writes the container header. With faststart, mp4/mov/3gp files get the moov atom moved to the front (movflags +faststart, a second pass over the file when the trailer is written) so browsers and NLEs can start playback before the whole file is downloaded. ```rust pub(crate) unsafe fn write_header( oc: *mut AVFormatContext, faststart: bool, ) -> Result<(), renderer_error::RenderEncodingError> { unsafe { let format_name_ptr = (*(*oc).oformat).name; let format_name = if format_name_ptr.is_null() { std::borrow::Cow::Borrowed("") } else { CStr::from_ptr(format_name_ptr).to_string_lossy() }; let mut opts: *mut AVDictionary = std::ptr::null_mut(); if faststart && ["mp4", "mov", "3gp"] .iter() .any(|container| format_name.contains(container)) { let key = CString::new("movflags").unwrap(); let value = CString::new("+faststart").unwrap(); av_dict_set(&mut opts, key.as_ptr(), value.as_ptr(), 0); } let status = avformat_write_header(oc, &mut opts); av_dict_free(&mut opts); if status < 0 { return Err(renderer_error::RenderEncodingError::FFmpegError( status, av_error_to_string(status), )); } Ok(()) } } ``` -------------------------------- ### Prepare codec options or default parameters per codec Source: https://docs.rs/fframes/latest/src/fframes/renderer/stream.rs.html Sets up a pointer to an empty AVDictionary and selects codec parameter overrides. Uses encoder_options.codec_params if present; otherwise, based on the codec name, uses a list of common x264 or x265 options (preset, tune, profile, etc.), or None for unknown codecs. ```rust let opts: *mut *mut AVDictionary = &mut std::ptr::null_mut(); let codec_options = match encoder_options.codec_params { Some(options) => Some(options), None if !(*codec).name.is_null() => { let codec_name = CStr::from_ptr((*codec).name).to_string_lossy(); match codec_name.as_ref() { "libx264" => Some( [ ("preset", "ultrafast"), ("tune", "animation"), ("profile", "main"), ("bframes", "2"), ("crf", "23"), ] .as_slice(), ), "libx265" => Some( [ ("preset", "ultrafast"), ("tune", "animation"), ("profile", "main"), ("crf", "23"), ("x265-params", "log-level=none"), ] .as_slice(), ), _ => None, } } _ => None, }; ``` -------------------------------- ### WASM video frame resolver setup and data types Source: https://docs.rs/fframes/latest/src/fframes/video_data.rs.html Defines VideoFrameData, VideoFrameResolver, a thread-local resolver, and set_video_frame_resolver for WASM targets. The resolver is called synchronously during render_frame to get a decoded frame, with the last argument indicating whether the frame is for a timeline preview. ```rust use crate::{FFramesContext, media::GeneralVideoFileMetadata, media::ImageData}; use fframes_media::VideoMedia; use std::sync::Arc; #[cfg(not(target_arch = "wasm32"))] use crate::error::Result; #[cfg(not(target_arch = "wasm32"))] use fframes_media::ImageMetadata; pub use fframes_media::{FrameConvertOptions, ResizeVideoFrame}; #[cfg(not(target_arch = "wasm32"))] use std::collections::HashMap; #[cfg(target_arch = "wasm32")] use std::cell::Cell; /// Data returned by the video frame resolver callback. #[cfg(target_arch = "wasm32")] pub struct VideoFrameData { pub url: String, /// Data URL fallback for timeline preview rendering (works inside SVG-as-image) pub preview_url: Option, pub width: u32, pub height: u32, } /// Function pointer type for resolving video frames from JS. /// Called synchronously during render_frame to get a decoded frame. /// The last argument tells whether the frame is requested for a timeline /// preview (which only needs the poster and must not steer the decode queue). #[cfg(target_arch = "wasm32")] pub type VideoFrameResolver = fn(&str, i64, bool) -> Option; #[cfg(target_arch = "wasm32")] thread_local! { static VIDEO_FRAME_RESOLVER: Cell> = Cell::new(None); } /// Set the video frame resolver callback. Called once during editor setup. /// The resolver is invoked synchronously from WASM during render_frame. #[cfg(target_arch = "wasm32")] pub fn set_video_frame_resolver(resolver: VideoFrameResolver) { VIDEO_FRAME_RESOLVER.with(|r| r.set(Some(resolver))); } ``` -------------------------------- ### Example: implementing define_scenes with zero-sized and borrowed scenes Source: https://docs.rs/fframes/latest/fframes/trait.Video.html Shows how to implement define_scenes for a Video. It creates a vector of scene references, including a zero-sized type (Intro) and a scene with data borrowed from self (self.chapter). Every scene must be bound to the &self lifetime or be a zero sized type. ```rust use fframes::{Scene, Scenes, Video}; #[derive(Debug)] struct Intro; #[derive(Debug)] struct Chapter { title: String, } impl Scene for Intro { /* duration, render_frame */ } impl Scene for Chapter { /* duration, render_frame */ } struct MyVideo { chapter: Chapter, } impl Video for MyVideo { fn define_scenes(&self) -> Scenes<'_> { let scenes: Vec<&dyn Scene> = vec![ // a zero sized type, so the reference can be created right here &Intro, // a scene with data is borrowed from `self` &self.chapter, ]; Scenes::from(scenes) } } ``` -------------------------------- ### new Source: https://docs.rs/fframes/latest/src/fframes/renderer/cli.rs.html Creates a new CLI Runner for the given video and render options. The runner is configured with default CPU backend, no args, no preview, and default output path 'out.mp4'. ```APIDOC ## Runner::new ### Description Creates a new CLI runner for rendering and inspecting a video. The runner executes commands such as `render`, `frame`, `strip`, `inspect`, `audio`, etc. when `run()` is called. ### Method Constructor function ### Signature ```rust pub fn new<'a, 'media: 'a, V: Video + Send + Sync>( video: &'a V, options: RenderOptions<'a, 'media>, ) -> Runner<'static, 'a, 'media, V> ``` ### Parameters - **video** (`&V`) - Required - The video to be processed. - **options** (`RenderOptions`) - Required - Rendering configuration options. ### Returns - `Runner<'static, 'a, 'media, V>` - A new runner instance. ### Defaults - Backend: `CpuRenderingBackend` - Args: `None` - Player: `None` - Default output: `out.mp4` ``` -------------------------------- ### Result::err example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::err, converting Ok to None and Err to Some. ```rust let x: Result = Ok(2); assert_eq!(x.err(), None); let x: Result = Err("Nothing here"); assert_eq!(x.err(), Some("Nothing here")); ``` -------------------------------- ### Minimal video with fframes::cli Source: https://docs.rs/fframes Minimal fframes video example. Requires the `cli` feature to run via `fframes::cli::new(...).run()`. Without `cli`, call `render` with an output path, a backend, and `RenderOptions`, or render single frames through `Previewer`. ```rust use fframes::{AudioMap, Duration, FFramesContext, Frame, RenderOptions, Svgr, Video, animation::Easing}; // Every file in the folder becomes a field; fonts are registered by family name. fframes::include_media_dir!(pub struct Media, "media"); struct Hello<'a> { media: &'a Media, title: &'a str, } impl Video for Hello<'_> { const FPS: usize = 30; const WIDTH: usize = 1920; const HEIGHT: usize = 1080; fn duration(&self) -> Duration<'_> { Duration::Seconds(3.0) } fn audio(&self) -> AudioMap<'_> { AudioMap::none() } fn render_frame<'a>(&'a self, frame: Frame, _ctx: &FFramesContext<'a, '_>) -> Svgr<'a> { let opacity = frame.animate(&fframes::timeline!( at 0.0 => 0.5, animate 0.0_f32 => 1.0, Easing::EaseOut )); fframes::svgr!( "Hello " {self.title} ) } } fn main() -> std::process::ExitCode { let media = Media::prepare().expect("embedded media"); let video = Hello { media: &media, title: "world" }; // `render`, `frame`, `strip`, `inspect`, `snapshot`, `audio` and more (feature `cli`). fframes::cli::new(&video, RenderOptions { media: Some(&media), ..Default::default() }).run() } ``` -------------------------------- ### is_err() examples Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Returns true if the result is Err. The examples test with Ok and Err values. ```rust let x: Result = Ok(-3); assert_eq!(x.is_err(), false); let x: Result = Err("Some error message"); assert_eq!(x.is_err(), true); ``` -------------------------------- ### Color usage example with svgr! macro Source: https://docs.rs/fframes/latest/src/fframes/color.rs.html Shows how to define Color constants and use them in an svgr! macro. Requires importing Color, Svgr, and svgr from crate::fframes. ```rust use crate::fframes::{Color, Svgr, svgr}; const WHITE: Color = Color::hex("#FFFFFF"); const SEMI_TRANSPARENT_RED: Color = Color::rgba(255, 0, 0, 128); svgr!(); ``` -------------------------------- ### Media Directory Scanning and Provider Construction Source: https://docs.rs/fframes/latest/src/fframes/renderer/media_directory.rs.html This snippet shows the core logic for scanning a directory, matching video file extensions, decoding audio data, and constructing a DynamicMediaProvider with the collected media. It handles video files by inserting them into a video_paths map and attempts to decode audio data for preloading. ```rust ("mp4" | "webm" | "mkv" | "avi" | "mov" | "flv" | "wmv" | "m4v", _) => { video_paths.lock()?.insert( filename.to_owned(), VideoMedia { path: path.to_owned(), metadata: None, }, ); if let Ok(audio_data) = crate::media::PreloadedAudioData::decode_raw_file_stereo(None, path) { audio_hash.lock()?.insert( filename.to_owned(), crate::AudioData::Preloaded(audio_data), ); } } _ => {} }; ``` ```rust let provider = DynamicMediaProvider::new( audio_hash.into_inner()?, image_hash.into_inner()?, subtitles_hash.into_inner()?, video_paths.into_inner()?, fontdata.into_inner()?, ); Ok(provider) ``` -------------------------------- ### Result::flatten nested example Source: https://docs.rs/fframes/latest/fframes/type.RenderEncodingResult.html Example showing that flatten only removes one level of nesting at a time. ```rust let x: Result, u32>, u32> = Ok(Ok(Ok("hello"))); assert_eq!(Ok(Ok("hello")), x.flatten()); assert_eq!(Ok("hello"), x.flatten().flatten()); ``` -------------------------------- ### Result::as_mut example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::as_mut, allowing mutable access to the contained value from a &mut Result. ```rust fn mutate(r: &mut Result) { match r.as_mut() { Ok(v) => *v = 42, Err(e) => *e = 0, } } let mut x: Result = Ok(2); mutate(&mut x); assert_eq!(x.unwrap(), 42); let mut x: Result = Err(13); mutate(&mut x); assert_eq!(x.unwrap_err(), 0); ``` -------------------------------- ### Result::map_or_default example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::map_or_default, returning the default value for the type U on Err or applying the function on Ok. ```rust let x: Result<_, &str> = Ok("foo"); let y: Result<&str, _> = Err("bar"); assert_eq!(x.map_or_default(|x| x.len()), 3); assert_eq!(y.map_or_default(|y| y.len()), 0); ``` -------------------------------- ### Previewer::new Source: https://docs.rs/fframes/latest/fframes/struct.Previewer.html Creates a new Previewer instance with the given video and render options. ```APIDOC ## Previewer::new ### Description Creates a new Previewer instance with the given video and render options. ### Method Constructor ### Signature pub fn new(video: &'a TVideo, options: &RenderOptions<'a, 'media>) -> FFramesRendererResult ### Parameters - **video** (&'a TVideo) - Required - The video to render. - **options** (&RenderOptions<'a, 'media>) - Required - The render options. ### Returns - **FFramesRendererResult** - The new Previewer instance or an error. ``` -------------------------------- ### Result::map_or example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::map_or, returning a default on Err or applying a function on Ok. The default is eagerly evaluated. ```rust let x: Result<_, &str> = Ok("foo"); assert_eq!(x.map_or(42, |v| v.len()), 3); let x: Result<&str, _> = Err("bar"); assert_eq!(x.map_or(42, |v| v.len()), 42); ``` -------------------------------- ### Previewer::new Source: https://docs.rs/fframes/latest/fframes/struct.Previewer.html Creates a new Previewer session for the given video and options. ```APIDOC ## Previewer::new ### Description Creates a new Previewer session for the given video and options. ### Method Constructor ### Signature `pub fn new(video: &Video, options: &PreviewerOptions) -> Result` ### Parameters - **video** (&Video) - Required - The video to render frames from. - **options** (&PreviewerOptions) - Required - Configuration options for the previewer. ### Returns - **Result** - A new Previewer instance or an error. ### Example ```rust let mut previewer = fframes::Previewer::new(&video, &options)?; ``` ``` -------------------------------- ### preview Source: https://docs.rs/fframes/latest/src/fframes/renderer/cli.rs.html Enables the `preview` command by providing a callback that plays a preview. The callback receives the video, render options, and a preview request. ```APIDOC ## Runner::preview ### Description Enables the `preview` command, typically with `fframes_native_player::cli_preview`. The provided callback is invoked when preview is requested. ### Method Builder method ### Signature ```rust pub fn preview<'r2>( self, play: impl FnOnce( &'a V, &RenderOptions<'a, 'media>, &super::PreviewRequest, ) -> Result<(), String> + 'r2, ) -> Runner<'r2, 'a, 'media, V, B, A> ``` ### Parameters - **play** (`FnOnce`) - Required - Callback that plays the preview. Takes `&V`, `&RenderOptions`, and `&PreviewRequest`, returns `Result<(), String>`. ### Returns - `Runner` with the preview callback set. ### Example ```rust let runner = Runner::new(&video, options).preview(|video, opts, req| { // play preview Ok(()) }); ``` ``` -------------------------------- ### Get subtitle phrase with get_subtitle_phrase Source: https://docs.rs/fframes/latest/fframes/struct.Frame.html Gets the subtitle phrase for the current frame using get_subtitle_phrase. Returns None if there is no phrase to render. ```rust let frame = fframes::Frame { ..Default::default() }; let phrase = frame.get_subtitle_phrase(&subtitles); ``` -------------------------------- ### fframes::cli::new Source: https://docs.rs/fframes/latest/src/fframes/renderer/cli.rs.html The main entry point for the fframes CLI, providing a ready-made command line for video binaries. ```APIDOC ## [CLI] fframes::cli::new ### Description Creates a ready-made command line for video binaries. One call gives every video the same tools for rendering and for checking the result without watching it. ### Method CLI ### Endpoint fframes::cli::new(&video, RenderOptions) ### Parameters - **video** (&Video) - Required - The video to render and inspect. - **options** (RenderOptions) - Required - Rendering options, e.g. media. ### Request Example ```rust let media = MyMedia::prepare().unwrap(); let video = MyVideo { media: &media }; fframes::cli::new(&video, RenderOptions { media: Some(&media), ..Default::default() }).run() ``` ### Response #### Success Response - **ExitCode** - The process exit code. #### Response Example ```rust std::process::ExitCode ``` ``` -------------------------------- ### option_duration! Source: https://docs.rs/fframes/latest/fframes/animation/macro.option_duration.html Macro to create an option duration value. Supports two forms: one with a start expression and one with both start and end expressions. ```APIDOC ## option_duration! ### Description Macro to create an option duration value. Supports two forms: one with a start expression and one with both start and end expressions. ### Syntax ```rust macro_rules! option_duration { ($start: expr) => { ... }; ($start: expr, $end:expr) => { ... }; } ``` ### Parameters - `$start` (expr) - Required - The start expression for the duration. - `$end` (expr) - Optional - The end expression for the duration. ### Usage This macro is used to define animation duration options. It can be called with a single expression or with two expressions separated by a comma. ### Example ```rust // Example usage with a single expression option_duration!(1.0); // Example usage with start and end expressions option_duration!(0.5, 1.5); ``` ``` -------------------------------- ### Result::map_or_else example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::map_or_else, applying a fallback function on Err or a function on Ok. Unpacks a successful result while handling an error. ```rust let k = 21; let x : Result<_, &str> = Ok("foo"); assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3); let x : Result<&str, _> = Err("bar"); assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42); ``` -------------------------------- ### Handle Preview command with player Source: https://docs.rs/fframes/latest/src/fframes/renderer/cli.rs.html Handles the `Preview` CLI command. Requires a real-time player configured via `fframes_native_player` and `.preview(fframes_native_player::cli_preview)`; otherwise returns an error suggesting `strip`, `frame`, or `render --draft`. Builds a `PreviewRequest` from CLI flags and drops the previewer before playing. ```rust Command::Preview(args) => { let Some(play) = player else { return Err("this binary has no real-time player: add the \ `fframes_native_player` crate and \ `.preview(fframes_native_player::cli_preview)`. Without a \ window use `strip`, `frame` or `render --draft`." .to_owned()); }; let request = super::PreviewRequest { start_frame: previewer .timeline() .resolve_frame(&args.at) .map_err(err)?, autoplay: !args.paused, looping: !args.no_loop, audio: !args.mute, backend: args.backend, }; let options = previewer.options().clone(); // Fonts and caches of the previewer are not needed by the player. drop(previewer); play(video, &options, &request).map(|()| ExitCode::SUCCESS) } ``` -------------------------------- ### KeyFramesAnimation::new constructor logic Source: https://docs.rs/fframes/latest/src/fframes/animation/animation.rs.html Builds a KeyFramesAnimation from a vector of tweens. The last tween's end is required; if not provided, the keyframe is ignored and the animation ends at the start of the last keyframe. The total duration is computed as the difference between the last tween's end (or start) and the first tween's start. ```rust // this duplicates the logic. The last keyframe end is required, if not provided the // keyframe is ignored and we end at the start of the last keyframe. let last_tween = tweens.last().unwrap(); let total_duration = last_tween.end.unwrap_or(last_tween.start) - tweens[0].start; KeyFramesAnimation { keyframes, total_duration, final_value: last_tween.to, } ``` -------------------------------- ### Track Preparation Loop with Audio Resolution and Effects Source: https://docs.rs/fframes/latest/src/fframes/audio_mix.rs.html This code prepares individual audio tracks for mixing. It resolves audio data, skips missing or lazy tracks, handles resampling, applies panning and ducking, and constructs a `PreparedTrack` with all necessary parameters. It also collects missing files and applies declicking options. ```rust let mut tracks = Vec::new(); for track in resolved { let audio = match media.and_then(|m| m.resolve_audio(&track.file)) { Some(AudioData::Preloaded(data)) => data, Some(AudioData::Lazy) => continue, None => { crate::diagnostics::report_missing_media( crate::diagnostics::MediaKind::Audio, &track.file, ); missing.push(track.file.clone()); continue; } }; let range = to_output(track.range.start.as_usize())..to_output(track.range.end.as_usize()); if range.is_empty() || audio.sample_rate == 0 { continue; } let source_rate = audio.sample_rate as f64; let ratio = source_rate / rate; let source_start = track.mix.offset as f64 * source_rate; let natural_end = range.start as f64 + (audio.samples.len() as f64 - source_start) / ratio; let resampler = (audio.sample_rate as usize != sample_rate) .then(|| SincResampler::new(source_rate, rate)); let pan = track.mix.pan.clamp(-1., 1.); let pan = if pan.abs() < 1e-6 { (1., 1.) } else if audio.is_stereo() { // Balance: attenuate the opposite side. let attenuation = (pan.abs() * std::f32::consts::FRAC_PI_2).cos(); if pan > 0. { (attenuation, 1.) } else { (1., attenuation) } } else { // Equal power, compensated to unity at the center. let x = (pan + 1.) * 0.5 * std::f32::consts::FRAC_PI_2; ( (std::f32::consts::SQRT_2 * x.cos()).min(1.), (std::f32::consts::SQRT_2 * x.sin()).min(1.), ) }; let duck_under = match track.mix.duck { Some(ducking) => merge_ranges( voices .iter() // A voice track does not duck itself. .filter(|v| { !(track.mix.voice && **v == (range.start as f64..range.end as f64)) }) .cloned() .collect(), ducking.merge_gap as f64 * rate, ), None => Vec::new(), }; tracks.push(PreparedTrack { file: track.file.clone(), left: audio.samples.as_ref(), right: audio.right.as_deref(), source_start, ratio, resampler, gain: db_to_gain(track.mix.gain_db), pan, mix: track.mix, fade_in: track.mix.fade_in as f64 * rate, fade_out: track.mix.fade_out as f64 * rate, declick_in: options.declick && track.mix.offset > 0., declick_out: options.declick && (range.end as f64) < natural_end - 1., range, duck_under, }); } Self { tracks, sample_rate, master_gain: db_to_gain(options.master_gain_db), limiter: options.limiter.map(|l| Limiter::new(l, sample_rate)), next_raw: None, output_range, total_samples, declick: options.declick, missing, } ``` -------------------------------- ### Result::map example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Example of Result::map, applying a function to the Ok value while leaving Err untouched. Prints each parsed number multiplied by two. ```rust let line = "1\n2\n3\n4\n"; for num in line.lines() { match num.parse::().map(|i| i * 2) { Ok(n) => println!("{n}"), Err(..) => {} } } ``` -------------------------------- ### new Source: https://docs.rs/fframes/latest/fframes/cli/fn.new.html Documentation for the `new` function in the `fframes::cli` module, which creates a command line interface for video operations. ```APIDOC ## `new` ### Description Creates a command line interface for the given video, supporting operations such as render, frame, strip, inspect, audio, and more. Call `.run()` to execute the CLI. ### Signature ```rust pub fn new<'a, 'media: 'a, V: Video + Send + Sync>( video: &'a V, options: RenderOptions<'a, 'media>, ) -> Runner<'static, 'a, 'media, V> ``` ### Parameters - **video** (`&'a V`) - Required - A reference to the video to operate on. - **options** (`RenderOptions<'a, 'media>`) - Required - Rendering options for the CLI. ### Returns - **Runner<'static, 'a, 'media, V>** - A runner that can be executed with `.run()`. ``` -------------------------------- ### is_ok_and() examples Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Returns true if the result is Ok and the value inside matches a predicate. The last example shows using as_ref() to avoid moving the value. ```rust let x: Result = Ok(2); assert_eq!(x.is_ok_and(|x| x > 1), true); let x: Result = Ok(0); assert_eq!(x.is_ok_and(|x| x > 1), false); let x: Result = Err("hey"); assert_eq!(x.is_ok_and(|x| x > 1), false); let x: Result = Ok("ownership".to_string()); assert_eq!(x.as_ref().is_ok_and(|x| x.len() > 1), true); println!("still alive {:?}", x); ``` -------------------------------- ### Implement MediaProvider for CombinedMediaProvider with delegation Source: https://docs.rs/fframes/latest/src/fframes/media_provider.rs.html This implementation of MediaProvider for CombinedMediaProvider delegates each resolve method to the first provider that returns a value, and populates font and image sources by iterating over all providers. The populate_image_source method is only compiled on non-wasm32 targets. ```rust impl<'a, const N: usize> MediaProvider<'a> for CombinedMediaProvider<'a, N> { fn resolve_audio(&self, name: &str) -> Option<&'a AudioData<'_>> { self.0 .iter() .find_map(|provider| provider.resolve_audio(name)) } fn resolve_image(&'a self, name: &str) -> Option<&'a media::ImageData<'a>> { self.0 .iter() .find_map(|provider| provider.resolve_image(name)) } fn resolve_subtitles(&self, name: &str) -> Option<&'a media::Subtitles<'_>> { self.0 .iter() .find_map(|provider| provider.resolve_subtitles(name)) } fn resolve_video(&'a self, name: &str) -> Option<&'a media::VideoMedia> { self.0 .iter() .find_map(|provider| provider.resolve_video(name)) } fn populate_font_source(&'a self, font_source: &mut dyn FontSource) { for provider in self.0.iter() { provider.populate_font_source(font_source); } } #[cfg(not(target_arch = "wasm32"))] fn populate_image_source( &'a self, image_data: &mut HashMap>, ) { for provider in self.0.iter() { provider.populate_image_source(image_data); } } } ``` -------------------------------- ### cloned() example for Result<&T, E> Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Maps a Result<&T, E> to Result by cloning the Ok value. Requires T: Clone. The example demonstrates with an integer reference. ```rust let val = 12; let x: Result<&i32, i32> = Ok(&val); assert_eq!(x, Ok(&12)); let cloned = x.cloned(); assert_eq!(cloned, Ok(12)); ``` -------------------------------- ### Creating an AudioMap with AudioTrack instances Source: https://docs.rs/fframes/latest/fframes/struct.AudioTrack.html Shows how to create an AudioMap from an array of AudioTrack instances. Each track is configured with methods like gain_db, fade_out, duck_under_voice, voice, and pan. The example uses AudioTimestamp variants Second and Eof to define ranges. ```rust use fframes::{AudioTrack, AudioTimestamp::*}; AudioMap::from([ AudioTrack::new("music.mp3", Second(0.)..Eof).gain_db(-14.).fade_out(2.).duck_under_voice(), AudioTrack::new("voice.wav", Second(1.5)..Eof).voice(), AudioTrack::new("whoosh.wav", Second(4.2)..Eof).pan(-0.5), ]) ``` -------------------------------- ### copied() example for Result<&T, E> Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Maps a Result<&T, E> to Result by copying the Ok value. Requires T: Copy. The example demonstrates with an integer reference. ```rust let val = 12; let x: Result<&i32, i32> = Ok(&val); assert_eq!(x, Ok(&12)); let copied = x.copied(); assert_eq!(copied, Ok(12)); ``` -------------------------------- ### Result::is_err_and examples Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Rust standard library examples for Result::is_err_and, testing error predicates on Err and Ok values. Uses Error from std::io. ```rust use std::io::{Error, ErrorKind}; let x: Result = Err(Error::new(ErrorKind::NotFound, "!")); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true); let x: Result = Err(Error::new(ErrorKind::PermissionDenied, "!")); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); let x: Result = Ok(123); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); let x: Result = Err("ownership".to_string()); assert_eq!(x.as_ref().is_err_and(|x| x.len() > 1), true); println!("still alive {:?}", x); ``` -------------------------------- ### render_cells: Process frames for sheet Source: https://docs.rs/fframes/latest/src/fframes/renderer/cli.rs.html Starts the render_cells function that processes a list of frames to produce sheet cells and frame reports. The snippet is truncated at the loop start. ```rust fn render_cells<'a, 'm: 'a, V: Video>( previewer: &mut Previewer<'a, 'm, V>, renderer: &mut dyn FrameRenderer, frames: &[usize], ) -> CliResult<(Vec, Vec)> { let mut cells = Vec::new(); let mut reports = Vec::new(); for &frame in frames { ``` -------------------------------- ### render function - Render video to output path Source: https://docs.rs/fframes/latest/src/fframes/renderer/renderer.rs.html Renders an fframes video to the specified output path using the provided video, render backend, and options. Sets up the renderer runtime, image source, and usvg options, then calls the backend's render method. Logs warnings for missing media and returns a result. ```rust pub fn render< 'a, 'media: 'a, TBackend: FFramesRenderBackend, TVideo: Video + Sync + Sized + Send, >( output: impl AsRef, video: &'a TVideo, render_backend: TBackend, options: &'a RenderOptions<'a, 'media>, ) -> FFramesRendererResult<()> { let logger = fframes_logger::make_logger(options.logger.clone()); let output = PathBuf::from(output.as_ref()); let scenes = video.define_scenes(); let FFramesRendererRuntime { timeline, time_base, mut font_source, } = FFramesRendererRuntime::new( TimeBase { fps: TVideo::FPS, sample_rate: options.audio_encoder_options.sample_rate, }, video, &scenes, options.media, )?; let mut image_source = HashMap::new(); if let Some(media) = options.media { media.populate_image_source(&mut image_source); } let usvg_options = usvgr::Options { image_data: Some(&image_source), font_family: options.default_font.to_string(), ..Default::default() }; if options.load_system_fonts { font_source.fontdb.load_system_fonts(); } let frame_range = options.output_frame_range(timeline.duration_in_frames); if frame_range.is_empty() { return Err(super::FFramesRendererError::Custom(format!( "frame range {:?} is empty or outside the video (0..{})", options.frame_range, timeline.duration_in_frames ))); } logger.init_frames_rendering(frame_range.len())?; let ctx = FFramesContext { time_base, mode: crate::FFramesMode::Renderer, media_source: options.media, duration_in_frames: timeline.duration_in_frames, scenes: timeline.scenes.as_ref(), font_source: Some(&font_source), abort_signal: options.abort_signal, current_video_size: VideoSize::new_scaled( TVideo::WIDTH, TVideo::HEIGHT, options.scale_resolution, ), }; render_backend.render( &output, video, logger.clone(), &usvg_options, options, font_source.as_db_ref(), &timeline, &ctx, )?; for (kind, name) in crate::diagnostics::take_missing_media() { logger.warn(&format!( "{kind:?} \"{name}\" was requested by render_frame but is not in the media provider" )); } Ok(()) } ``` -------------------------------- ### Emit media processing start event Source: https://docs.rs/fframes/latest/src/fframes/renderer/fframes_logger.rs.html Emits a 'media' event when media processing starts. The message includes the media count and metadata includes the file count. ```rust self.emit( "media", format!("processing {media_count} media files"), &[("files", media_count.to_string())], ); ``` -------------------------------- ### Previewer::options Source: https://docs.rs/fframes/latest/fframes/struct.Previewer.html Returns the render options. ```APIDOC ## Previewer::options ### Description Returns the render options. ### Method Getter ### Signature pub fn options(&self) -> &RenderOptions<'a, 'media> ### Parameters None ### Returns - **&RenderOptions<'a, 'media>** - The render options. ``` -------------------------------- ### iter example Source: https://docs.rs/fframes/latest/fframes/error/type.Result.html Demonstrates `iter`, which returns an iterator over the possibly contained value, yielding one value if the result is `Ok` and none otherwise. The example asserts both `Ok` and `Err` cases. ```rust let x: Result = Ok(7); assert_eq!(x.iter().next(), Some(&7)); let x: Result = Err("nothing!"); assert_eq!(x.iter().next(), None); ```