Skip to main content

VideoHandle

Struct VideoHandle 

Source
pub struct VideoHandle<'a> { /* private fields */ }
Expand description

Video frame extraction operations.

Obtained via MediaFile::video or MediaFile::video_track. Each extraction method creates a fresh decoder, seeks to the relevant position, and decodes frames. The decoder is dropped when the method returns.

Frames are returned as DynamicImage, with pixel format controlled by ExtractOptions.

Implementations§

Source§

impl<'a> VideoHandle<'a>

Source

pub fn filter(self, filter_spec: &str) -> FilterChainHandle<'a>

Start a chainable FFmpeg filter pipeline.

This is a convenience wrapper around frame_with_filter for incremental filter construction.

Source

pub fn frame( &mut self, frame_number: u64, ) -> Result<DynamicImage, UnbundleError>

Extract a single frame by frame number (0-indexed).

Seeks to the nearest keyframe before the target and decodes forward until the requested frame is reached. Uses default output settings (RGB8, source resolution).

§Errors
§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let frame = unbundler.video().frame(100)?;
frame.save("frame_100.png")?;
Source

pub fn frame_with_options( &mut self, frame_number: u64, config: &ExtractOptions, ) -> Result<DynamicImage, UnbundleError>

Extract a single frame with custom configuration.

Like frame but respects the pixel format, resolution, and hardware acceleration settings from the given ExtractOptions.

§Errors

Same as frame, plus UnbundleError::Cancelled if cancellation is requested.

§Example
use unbundle::{ExtractOptions, MediaFile, PixelFormat, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let config = ExtractOptions::new()
    .with_pixel_format(PixelFormat::Gray8)
    .with_resolution(Some(320), None);
let frame = unbundler.video().frame_with_options(100, &config)?;
Source

pub fn frame_with_filter( &mut self, frame_number: u64, filter_spec: &str, ) -> Result<DynamicImage, UnbundleError>

Extract a single frame, process it through a custom FFmpeg filter graph, and return the filtered image.

filter_spec uses standard FFmpeg filter syntax (for example, "scale=320:240", "hflip", "eq=brightness=0.05").

§Errors

Same as frame, plus UnbundleError::FilterGraphError if filter graph creation or execution fails.

§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let frame = unbundler
    .video()
    .frame_with_filter(0, "scale=320:240,eq=contrast=1.1")?;
frame.save("filtered.png")?;
Source

pub fn frame_with_filter_with_options( &mut self, frame_number: u64, filter_spec: &str, config: &ExtractOptions, ) -> Result<DynamicImage, UnbundleError>

Extract a single frame with a custom FFmpeg filter graph and extraction options.

Like frame_with_filter, but also respects output pixel format, target resolution, and cancellation from the provided ExtractOptions.

§Errors

Returns UnbundleError::Cancelled if cancellation is requested, or any error from frame_with_filter.

Source

pub fn frame_at( &mut self, timestamp: Duration, ) -> Result<DynamicImage, UnbundleError>

Extract a single frame at a specific timestamp.

Converts the timestamp to a frame number using the video’s frame rate and delegates to frame.

§Errors

Returns UnbundleError::InvalidTimestamp if the timestamp exceeds the media duration, or any error from frame.

§Example
use unbundle::{MediaFile, UnbundleError};
use std::time::Duration;

let mut unbundler = MediaFile::open("input.mp4")?;
let frame = unbundler.video().frame_at(Duration::from_secs(30))?;
frame.save("frame_at_30s.png")?;
Source

pub fn frame_at_with_options( &mut self, timestamp: Duration, config: &ExtractOptions, ) -> Result<DynamicImage, UnbundleError>

Extract a single frame at a timestamp with custom configuration.

Like frame_at but respects the pixel format, resolution, and hardware acceleration settings from the given ExtractOptions.

§Errors

Same as frame_at, plus UnbundleError::Cancelled if cancellation is requested.

§Example
use std::time::Duration;

use unbundle::{ExtractOptions, MediaFile, PixelFormat, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let config = ExtractOptions::new()
    .with_pixel_format(PixelFormat::Rgba8);
let frame = unbundler.video().frame_at_with_options(
    Duration::from_secs(30),
    &config,
)?;
Source

pub fn frame_and_metadata( &mut self, frame_number: u64, ) -> Result<(DynamicImage, FrameMetadata), UnbundleError>

Extract a single frame by number, returning both the image and its FrameMetadata metadata.

This combines frame extraction with metadata collection (PTS, keyframe flag, picture type) in a single decode pass.

§Errors

Same as frame.

§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let (image, info) = unbundler.video().frame_and_metadata(42)?;
println!("PTS: {:?}, keyframe: {}", info.pts, info.is_keyframe);
Source

pub fn frame_and_metadata_with_options( &mut self, frame_number: u64, config: &ExtractOptions, ) -> Result<(DynamicImage, FrameMetadata), UnbundleError>

Extract a single frame with FrameMetadata and custom configuration.

Like frame_and_metadata but respects the pixel format, resolution, and hardware acceleration settings from the given ExtractOptions.

§Errors

Same as frame_and_metadata, plus UnbundleError::Cancelled if cancellation is requested.

§Example
use unbundle::{ExtractOptions, MediaFile, PixelFormat, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let config = ExtractOptions::new()
    .with_pixel_format(PixelFormat::Gray8);
let (image, info) = unbundler.video().frame_and_metadata_with_options(42, &config)?;
Source

pub fn frames_and_metadata( &mut self, range: FrameRange, ) -> Result<Vec<(DynamicImage, FrameMetadata)>, UnbundleError>

Extract multiple frames with their FrameMetadata metadata.

Like frames but returns (DynamicImage, FrameMetadata) pairs, giving access to PTS, keyframe flags, and picture types for every extracted frame.

§Errors

Same as frames.

§Example
use unbundle::{FrameRange, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let results = unbundler.video().frames_and_metadata(FrameRange::Range(0, 9))?;
for (image, info) in &results {
    println!("Frame {} — type {:?}", info.frame_number, info.frame_type);
}
Source

pub fn frames_and_metadata_with_options( &mut self, range: FrameRange, config: &ExtractOptions, ) -> Result<Vec<(DynamicImage, FrameMetadata)>, UnbundleError>

Extract multiple frames with FrameMetadata and progress/cancellation.

Like frames_with_options but includes FrameMetadata for each frame.

§Errors

Same as frames_with_options.

Source

pub fn save_frame<P: AsRef<Path>>( &mut self, frame_number: u64, path: P, ) -> Result<(), UnbundleError>

Extract a frame and save it directly to a file.

Convenience method that combines frame with DynamicImage::save. The output format is inferred from the file extension.

§Errors

Returns errors from frame, or UnbundleError::ImageError if the image cannot be written.

§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
unbundler.video().save_frame(0, "first_frame.png")?;
Source

pub fn save_frame_at<P: AsRef<Path>>( &mut self, timestamp: Duration, path: P, ) -> Result<(), UnbundleError>

Extract a frame at a timestamp and save it directly to a file.

Convenience method that combines frame_at with DynamicImage::save. The output format is inferred from the file extension.

§Errors

Returns errors from frame_at, or UnbundleError::ImageError if the image cannot be written.

§Example
use std::time::Duration;

use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
unbundler.video().save_frame_at(Duration::from_secs(5), "frame_5s.png")?;
Source

pub fn stream_copy<P: AsRef<Path>>( &mut self, path: P, ) -> Result<(), UnbundleError>

Copy the video stream verbatim to a file without re-encoding.

Unlike frame extraction methods, this copies packets directly from the input stream, preserving the original codec and quality. The output container format is inferred from the file extension.

This is equivalent to ffmpeg -i input.mp4 -an -sn -c:v copy output.mp4.

§Errors
§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
unbundler.video().stream_copy("output.mp4")?;
Source

pub fn stream_copy_range<P: AsRef<Path>>( &mut self, path: P, start: Duration, end: Duration, ) -> Result<(), UnbundleError>

Copy a video segment verbatim to a file without re-encoding.

Like stream_copy but copies only packets between start and end. Because there is no re-encoding, the actual boundaries are aligned to packet/keyframe boundaries.

§Errors
Source

pub fn stream_copy_with_options<P: AsRef<Path>>( &mut self, path: P, config: &ExtractOptions, ) -> Result<(), UnbundleError>

Copy the video stream verbatim to a file with cancellation support.

Like stream_copy but accepts an ExtractOptions for cancellation.

§Errors

Returns UnbundleError::Cancelled if cancellation is requested, or any error from stream_copy.

Source

pub fn stream_copy_range_with_options<P: AsRef<Path>>( &mut self, path: P, start: Duration, end: Duration, config: &ExtractOptions, ) -> Result<(), UnbundleError>

Copy a video segment verbatim to a file with cancellation support.

Like stream_copy_range but accepts an ExtractOptions.

Source

pub fn stream_copy_to_memory( &mut self, container_format: &str, ) -> Result<Vec<u8>, UnbundleError>

Copy the video stream verbatim to memory without re-encoding.

container_format is the FFmpeg short name for the output container (for example: "matroska", "mp4", "mpegts").

§Errors
Source

pub fn stream_copy_range_to_memory( &mut self, container_format: &str, start: Duration, end: Duration, ) -> Result<Vec<u8>, UnbundleError>

Copy a video segment verbatim to memory without re-encoding.

Like stream_copy_to_memory but copies only packets between start and end.

§Errors
Source

pub fn frames( &mut self, range: FrameRange, ) -> Result<Vec<DynamicImage>, UnbundleError>

Extract multiple frames according to the specified range.

See FrameRange for the available selection modes.

§Errors

Returns errors from individual frame extraction, or UnbundleError::NoVideoStream if the file has no video.

§Example
use unbundle::{FrameRange, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let frames = unbundler.video().frames(FrameRange::Range(0, 9))?;
assert_eq!(frames.len(), 10);
Source

pub fn for_each_frame<F>( &mut self, range: FrameRange, callback: F, ) -> Result<(), UnbundleError>

Process frames one at a time without collecting them into a Vec.

This is a streaming alternative to frames that calls callback for each decoded frame. The callback receives the frame number and the decoded image. Processing stops if the callback returns an error.

§Errors

Returns the first error from decoding or from the callback.

§Example
use unbundle::{FrameRange, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
unbundler.video().for_each_frame(
    FrameRange::Range(0, 9),
    |frame_number, image| {
        image.save(format!("frame_{frame_number}.png"))?;
        Ok(())
    },
)?;
Source

pub fn frames_with_options( &mut self, range: FrameRange, config: &ExtractOptions, ) -> Result<Vec<DynamicImage>, UnbundleError>

Extract multiple frames with progress reporting and cancellation.

Like frames but accepts an ExtractOptions for progress callbacks and cancellation support.

§Errors

Returns UnbundleError::Cancelled if cancellation is requested, or any error from frames.

§Example
use std::sync::Arc;

use unbundle::{ExtractOptions, FrameRange, MediaFile, ProgressCallback, ProgressInfo, UnbundleError};

struct PrintProgress;
impl ProgressCallback for PrintProgress {
    fn on_progress(&self, info: &ProgressInfo) {
        println!("Frame {}/{}", info.current, info.total.unwrap_or(0));
    }
}

let mut unbundler = MediaFile::open("input.mp4")?;
let config = ExtractOptions::new()
    .with_progress(Arc::new(PrintProgress));
let frames = unbundler.video().frames_with_options(
    FrameRange::Range(0, 9),
    &config,
)?;
Source

pub fn for_each_frame_with_options<F>( &mut self, range: FrameRange, config: &ExtractOptions, callback: F, ) -> Result<(), UnbundleError>

Process frames one at a time with progress reporting and cancellation.

Like for_each_frame but accepts an ExtractOptions.

§Errors

Returns UnbundleError::Cancelled if cancellation is requested, or any error from decoding or the callback.

§Example
use unbundle::{CancellationToken, ExtractOptions, FrameRange, MediaFile, UnbundleError};

let token = CancellationToken::new();
let config = ExtractOptions::new()
    .with_cancellation(token.clone());

let mut unbundler = MediaFile::open("input.mp4")?;
unbundler.video().for_each_frame_with_options(
    FrameRange::Range(0, 99),
    &config,
    |frame_number, image| {
        image.save(format!("frame_{frame_number}.png"))?;
        Ok(())
    },
)?;
Source

pub fn for_each_raw_frame<F>( &mut self, range: FrameRange, callback: F, ) -> Result<(), UnbundleError>

Process decoded frames as zero-copy byte slices plus metadata.

Unlike for_each_frame, this avoids conversion to DynamicImage. The callback receives a borrowed RawFrameView valid for the duration of that callback call.

Source

pub fn for_each_raw_frame_with_options<F>( &mut self, range: FrameRange, config: &ExtractOptions, callback: F, ) -> Result<(), UnbundleError>

Process decoded frames as zero-copy byte slices plus metadata, with progress/cancellation support.

Source

pub fn detect_scenes( &mut self, config: Option<SceneDetectionOptions>, ) -> Result<Vec<SceneChange>, UnbundleError>

Detect scene changes (shot boundaries) in the video.

Uses FFmpeg’s scdet filter to analyse every frame and return a list of SceneChange entries.

An optional SceneDetectionOptions controls the detection threshold. Pass None for defaults (threshold 10.0).

§Errors
§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let scenes = unbundler.video().detect_scenes(None)?;
println!("Found {} scene changes", scenes.len());
Source

pub fn detect_scenes_with_options( &mut self, scene_config: Option<SceneDetectionOptions>, config: &ExtractOptions, ) -> Result<Vec<SceneChange>, UnbundleError>

Detect scene changes with cancellation support.

Like detect_scenes but accepts an ExtractOptions for cancellation.

Source

pub fn export_gif<P: AsRef<Path>>( &mut self, path: P, range: FrameRange, gif_config: &GifOptions, ) -> Result<(), UnbundleError>

Export frames as an animated GIF to a file.

Extracts frames matching the given FrameRange, scales them according to GifOptions, and writes the result as an animated GIF.

§Errors
§Example
use std::time::Duration;
use unbundle::{FrameRange, GifOptions, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let config = GifOptions::new().width(320).frame_delay(10);
unbundler.video().export_gif(
    "output.gif",
    FrameRange::TimeRange(Duration::from_secs(0), Duration::from_secs(5)),
    &config,
)?;
Source

pub fn export_gif_to_memory( &mut self, range: FrameRange, gif_config: &GifOptions, ) -> Result<Vec<u8>, UnbundleError>

Export frames as an animated GIF into memory.

Like export_gif but returns the raw GIF bytes instead of writing to a file.

§Errors

Same as export_gif.

Source

pub fn analyze_group_of_pictures( &mut self, ) -> Result<GroupOfPicturesInfo, UnbundleError>

Analyze the Group of Pictures structure of the video stream.

Scans all video packets (without decoding) to identify keyframes and compute Group of Pictures statistics such as average, minimum and maximum sequence size.

§Errors
§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let group_of_pictures = unbundler.video().analyze_group_of_pictures()?;
println!(
    "Keyframes: {}, Average Group of Pictures: {:.1}",
    group_of_pictures.keyframes.len(),
    group_of_pictures.average_group_of_pictures_size
);
Source

pub fn keyframes(&mut self) -> Result<Vec<KeyFrameMetadata>, UnbundleError>

Return a list of all keyframes in the video stream.

This is a convenience wrapper around analyze_group_of_pictures that returns only the keyframe list.

§Errors

Same as analyze_group_of_pictures.

Source

pub fn analyze_variable_framerate( &mut self, ) -> Result<VariableFrameRateAnalysis, UnbundleError>

Analyze the video stream for variable frame rate (VFR).

Scans all video packet PTS values and computes timing statistics. The result indicates whether the stream is VFR, plus min/max/mean FPS and per-frame PTS values.

§Errors
§Example
use unbundle::{MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let analysis = unbundler.video().analyze_variable_framerate()?;
println!("VFR: {}, mean FPS: {:.2}", analysis.is_variable_frame_rate, analysis.mean_frames_per_second);
Source

pub fn frame_stream( &mut self, range: FrameRange, config: ExtractOptions, ) -> Result<FrameStream, UnbundleError>

Create an async stream of decoded video frames.

Returns a FrameStream that yields (frame_number, DynamicImage) pairs from a background blocking thread. The stream implements tokio_stream::Stream and can be used with StreamExt combinators.

A fresh demuxer is opened internally so this method returns immediately and the mutable borrow on the unbundler is released.

§Errors

Returns UnbundleError::NoVideoStream if the file has no video stream (validated eagerly before spawning the background thread).

§Example
use tokio_stream::StreamExt;

use unbundle::{ExtractOptions, FrameRange, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let mut stream = unbundler
    .video()
    .frame_stream(FrameRange::Range(0, 9), ExtractOptions::new())?;

while let Some(result) = stream.next().await {
    let (frame_number, image) = result?;
    image.save(format!("frame_{frame_number}.png"))?;
}
Source

pub fn frame_iter( self, range: FrameRange, ) -> Result<FrameIterator<'a>, UnbundleError>

Create a lazy iterator over decoded video frames.

Unlike frames, which decodes everything up-front, this returns a FrameIterator that decodes one frame at a time on each next() call. This is ideal when you want to stop early or process frames one by one without buffering the entire set.

The iterator borrows the underlying MediaFile mutably and releases it when dropped.

§Errors

Returns UnbundleError::NoVideoStream if the file has no video, or validation errors from the range.

§Example
use unbundle::{FrameRange, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let iter = unbundler.video().frame_iter(FrameRange::Range(0, 9))?;

for result in iter {
    let (frame_number, image) = result?;
    image.save(format!("frame_{frame_number}.png"))?;
}
Source

pub fn frame_iter_with_options( self, range: FrameRange, output_config: FrameOutputOptions, ) -> Result<FrameIterator<'a>, UnbundleError>

Create a lazy iterator with custom output configuration.

Like frame_iter but uses the given FrameOutputOptions for pixel format and resolution settings.

§Errors

Returns errors from frame_iter.

Source

pub fn frames_parallel( &mut self, range: FrameRange, config: &ExtractOptions, ) -> Result<Vec<DynamicImage>, UnbundleError>

Extract multiple frames in parallel using rayon.

Splits the requested frames across worker threads, each with its own demuxer and decoder. Returns frames sorted by frame number.

This is most effective for large frame sets where frames are spread across the video (e.g. FrameRange::Interval or FrameRange::Specific with widely spaced numbers). For small ranges, sequential extraction is often faster due to per-thread file-open overhead.

§Errors

Returns UnbundleError::NoVideoStream if the file has no video stream, or errors from individual worker threads.

§Example
use unbundle::{ExtractOptions, FrameRange, MediaFile, UnbundleError};

let mut unbundler = MediaFile::open("input.mp4")?;
let config = ExtractOptions::new();
let frames = unbundler
    .video()
    .frames_parallel(FrameRange::Interval(100), &config)?;
println!("Got {} frames", frames.len());

Auto Trait Implementations§

§

impl<'a> Freeze for VideoHandle<'a>

§

impl<'a> !RefUnwindSafe for VideoHandle<'a>

§

impl<'a> !Send for VideoHandle<'a>

§

impl<'a> !Sync for VideoHandle<'a>

§

impl<'a> Unpin for VideoHandle<'a>

§

impl<'a> !UnwindSafe for VideoHandle<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.