Skip to main content

PreviewPlayer

Struct PreviewPlayer 

Source
pub struct PreviewPlayer { /* private fields */ }
Expand description

Drives real-time playback of a single media file.

PreviewPlayer decodes a video/audio file, synchronises video frame presentation to an audio master clock, and delivers frames to a registered FrameSink.

§Usage

let mut player = PreviewPlayer::open(Path::new("clip.mp4"))?;
player.set_sink(Box::new(MySink::new()));
player.play();
player.run()?;

Implementations§

Source§

impl PreviewPlayer

Source

pub fn open(path: &Path) -> Result<Self, PreviewError>

Open a media file and prepare for playback.

Probes the file to detect audio/video streams, then opens a DecodeBuffer for the video stream (when present). Returns PreviewError if the file is missing, unreadable, or contains neither a video nor an audio stream.

Audio-only files (MP3, AAC, WAV, FLAC, …) are fully supported: run() will pace itself via the audio master clock and deliver no video frames. Callers should drain samples via pop_audio_samples.

§Errors

Returns PreviewError if the file cannot be probed or decoded.

Source

pub fn set_sink(&mut self, sink: Box<dyn FrameSink>)

Register the frame sink. Must be called before run.

Source

pub fn play(&self)

Start (or resume) playback.

Clears the paused and stopped flags. Must be called before run.

Source

pub fn pause(&self)

Pause playback. run will spin-sleep until play is called again.

Source

pub fn stop(&mut self)

Stop playback.

run returns after the current frame completes.

Source

pub fn stop_handle(&self) -> Arc<AtomicBool>

Returns a cloneable handle to the stop signal.

Storing true into the returned Arc<AtomicBool> has the same effect as calling stop and is safe to call from any context, including from within a FrameSink::push_frame callback.

§Example
let stop = player.stop_handle();
player.set_sink(Box::new(MySink { stop, max_frames: 10 }));
player.play();
player.run()?;
Source

pub fn pause_handle(&self) -> Arc<AtomicBool>

Returns a cloneable handle to the pause flag.

Storing true pauses run; storing false resumes it. Safe to call from any context, including from a UI thread running concurrently with run.

§Example
let pause = player.pause_handle();
let stop  = player.stop_handle();

std::thread::spawn(move || { player.play(); let _ = player.run(); });

pause.store(true, Ordering::Release);   // pause from UI thread
pause.store(false, Ordering::Release);  // resume
stop.store(true, Ordering::Release);    // stop
Source

pub fn pop_frame(&mut self) -> FrameResult

Pop the next decoded video frame.

Delegates to DecodeBuffer::pop_frame. Blocks until a frame is available. Returns FrameResult::Eof at end of file or for audio-only files.

Source

pub fn seek(&mut self, target_pts: Duration) -> Result<(), PreviewError>

Frame-accurate seek to target_pts.

Delegates to DecodeBuffer::seek. Returns Ok(()) immediately for audio-only files (no video stream to seek).

§Errors

Returns PreviewError if the seek fails.

Source

pub fn seek_coarse(&mut self, target_pts: Duration) -> Result<(), PreviewError>

Coarse seek to the nearest I-frame at or before target_pts.

Delegates to DecodeBuffer::seek_coarse. Faster than seek because it skips the forward-decode discard phase. The first frame after this call will be at the nearest preceding I-frame, which may be up to ±½ GOP from target_pts (typically ±1–2 s for H.264 at default settings).

Typical use: call repeatedly while a scrub bar is being dragged; call seek on drag release for frame accuracy.

// Scrub-bar drag handler:
player.seek_coarse(drag_pts)?;  // fast, called many times

// Drag released:
player.seek(release_pts)?;      // exact, called once
§Errors

Returns PreviewError if the seek fails.

Source

pub fn use_proxy_if_available(&mut self, proxy_dir: &Path) -> bool

If a proxy file for this media exists in proxy_dir, use it transparently.

Must be called before play. Returns true if a proxy was found and activated; returns false if no proxy exists (original file continues to be used).

Proxy lookup order: halfquartereighth; first match wins.

When a proxy is active, FrameSink::push_frame delivers frames at the proxy’s native resolution. Callers should not assume a fixed resolution.

If called after play, logs a warning and returns false.

Source

pub fn active_source(&self) -> &Path

Returns the path currently being decoded — either the original file or the activated proxy.

Source

pub fn set_av_offset(&self, ms: i64)

Set the A/V offset correction in milliseconds.

  • Positive value: video is delayed by ms ms relative to the audio clock (video PTS is shifted down in the sync comparison).
  • Negative value: audio is delayed by ms ms relative to video (video PTS is shifted up in the sync comparison).

Values outside ±5 000 ms are clamped and a warning is logged. Safe to call from any thread while run is executing.

Source

pub fn av_offset(&self) -> i64

Returns the current A/V offset in milliseconds (default: 0).

Safe to call from any thread while run is executing.

Source

pub fn av_offset_handle(&self) -> Arc<AtomicI64>

Returns a cloneable handle to the A/V offset atomic.

Writing a value into the returned Arc<AtomicI64> has the same effect as calling set_av_offset and is safe to do from any thread while run is executing.

Note: the handle stores the raw millisecond value without clamping. Values outside ±5 000 ms written directly to the handle will be applied as-is by run(); prefer set_av_offset when clamping is desired.

§Example
let av_handle   = player.av_offset_handle();
let stop_handle = player.stop_handle();

std::thread::spawn(move || { player.play(); let _ = player.run(); });

// Adjust A/V sync from the UI thread without stopping playback.
av_handle.store(200, std::sync::atomic::Ordering::Relaxed);
stop_handle.store(true, std::sync::atomic::Ordering::Release);
Source

pub fn set_rate(&self, rate: f64)

Set the playback rate.

Values ≤ 0.0 are silently ignored — the rate remains unchanged.

The new rate takes effect on the next frame’s sleep calculation inside run. Safe to call from any thread while run() is executing (same contract as set_av_offset).

  • 1.0 — real-time (default)
  • 2.0 — twice real-time (sleep halved)
  • 0.5 — half real-time (sleep doubled)
Source

pub fn rate_handle(&self) -> Arc<AtomicU64>

Returns a cloneable handle to the rate atomic.

Writing new_rate.to_bits() into the returned Arc<AtomicU64> has the same effect as calling set_rate and is safe to do from any thread while run is executing.

Note: the handle does not validate the value; storing bits that correspond to ≤ 0.0 or NaN will produce undefined sleep behaviour. Prefer set_rate when the validation guard is desired.

§Example
let rate   = player.rate_handle();
let stop   = player.stop_handle();

std::thread::spawn(move || { player.play(); let _ = player.run(); });

// Double speed from the UI thread without stopping playback.
rate.store(2.0_f64.to_bits(), std::sync::atomic::Ordering::Relaxed);
stop.store(true, std::sync::atomic::Ordering::Release);
Source

pub fn current_pts(&self) -> Duration

Returns the PTS of the most recently presented frame.

Returns Duration::ZERO before the first frame has been presented. Safe to call from any thread while run is executing.

§Example
let pts_handle = Arc::new(Mutex::new(Duration::ZERO));
let pts_clone  = Arc::clone(&pts_handle);

std::thread::spawn(move || {
    player.play();
    let _ = player.run();
});

// UI thread: poll current position to drive a seek bar.
loop {
    let pos = player.current_pts();
    update_seek_bar(pos);
    std::thread::sleep(std::time::Duration::from_millis(16));
}
Source

pub fn duration(&self) -> Option<Duration>

Returns the container-reported duration of the media file, if known.

Returns None for live or streaming sources where the container does not report a duration. Use the returned value to size a seek bar range:

if let Some(total) = player.duration() {
    let progress = player.current_pts().as_secs_f64() / total.as_secs_f64();
    seek_bar.set_fraction(progress);
}
Source

pub fn pop_audio_samples(&self, n_samples: usize) -> Vec<f32>

Pull up to n_samples interleaved stereo f32 PCM samples at 48 kHz.

Intended for use inside an audio output callback:

let samples = player.pop_audio_samples(buffer_size);
output_buffer[..samples.len()].copy_from_slice(&samples);
// fill remainder with silence when samples.len() < buffer_size (underrun)

Advances the audio master clock by the number of stereo frames consumed (samples.len() / 2).

Returns an empty Vec when:

  • the file has no audio track,
  • n_samples is 0,
  • playback is paused or stopped, or
  • the ring buffer is empty (underrun — caller should output silence).
Source

pub fn run(&mut self) -> Result<(), PreviewError>

A/V sync presentation loop.

Blocks until stop is called or the end of file is reached. Must be called from the presentation thread.

Video PTS is compared against the master clock:

  • Early frames (video PTS > clock + 1 frame period): sleep.
  • Late frames (video PTS < clock − 1 frame period): dropped.

For video-only files the System clock (Instant) drives real-time pacing. For files with audio the Audio clock drives sync once pop_audio_samples has been called at least once; before that, frames are presented immediately.

§Errors

Returns PreviewError if a frame cannot be presented to the sink.

Trait Implementations§

Source§

impl Drop for PreviewPlayer

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

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, 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.