Skip to main content

Crate egui_sharkplayer

Crate egui_sharkplayer 

Source
Expand description

A hardware-accelerated video widget for egui, backed by libmpv2.

This crate provides an immediate-mode video player for eframe applications.

§Overview

  • PlayerState: Manages the libmpv context, media properties, and playback state. This requires access to the graphics context and must be initialized once using the eframe::CreationContext.

    A single PlayerState maps to a single video stream. Displaying multiple videos simultaneously requires independent state instances.

  • SharkPlayer: The actual UI widget. This is what you create in your ui method.

The video player works best with the glow backend because libmpv2’s render API only supports OpenGL. When using the wgpu feature, instead of a direct VRAM copy, image data has to roundtrip through main system memory. If at all possible, use glow and disable the wgpu feature.

Because playback is driven with mpv, and video frames are rendered straight into an OpenGL framebuffer, this only works when using eframe’s glow rendering backend; wgpu is not supported.

§Features

  • Integrated contol overlays (play/pause, volume, seekbar, info overlay, etc.)
  • Fullscreening support

§Quick Start

use eframe::egui;
use egui_sharkplayer::{PlayerState, SharkPlayer};

struct App {
    player: PlayerState,
}

impl App {
    fn new(cc: &eframe::CreationContext<'_>) -> Self {
        let player = PlayerState::new(cc).expect("failed to initialize player");
        player.load_file("video.mp4").expect("failed to load video.mp4");
        Self { player }
    }
}

impl eframe::App for App {
    fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
        // Required: see "Cleaning up".
        self.player.destroy_gl_resources();
    }

    fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show_inside(ui, |ui| {
            ui.add(SharkPlayer::new(&mut self.player));
        });
    }
}

fn main() {
    eframe::run_native(
        "Sharkplayer",
        eframe::NativeOptions::default(),
        Box::new(|cc| Ok(Box::new(App::new(cc)))),
    )
    .unwrap();
}

If you want to play multiple videos at the same time, you’ll need to have multiple PlayerStates.

§Player Size

By default, the widget claims all the space available in its panel. However, it’s possible to contrain one of the axes using SharkPlayer::sizing to pin one axis instead — the other is derived from the video’s aspect ratio, so the player doesn’t letterbox.

ui.add(SharkPlayer::new(player).sizing(Sizing::Width(640.0)));

§Styling Controls

For the most part, the controls use standard egui styling, but some components have special styling options.

§Bar Height

The player bar has a default height, but it can be overridden with SharkPlayer::bar_height.

ui.add(
    SharkPlayer::new(player)
        .sizing(Sizing::Height(360.0))
        .bar_height(32.0),
);

§Custom icons

To customize which icons are used for the controls, you need a ControlsIconProvider.

use egui_sharkplayer::{ControlsIconProvider, PlayerState, SharkPlayer};

struct Icons;

impl ControlsIconProvider for Icons {
    fn play(&self) -> egui::WidgetText { "Play".into() }
    fn pause(&self) -> egui::WidgetText { "Pause".into() }
}

ui.add(SharkPlayer::new_with_icons(player, Icons));

§Cleaning Up

To clean up the player’s OpenGL resources, call PlayerState::destroy_gl_resources from eframe::App::on_exit.

This isn’t strictly necessary it’s fine to leak VRAM, like if the process stops when the UI closes.

Structs§

DefaultControlsIconProvider
The default ControlsIconProvider.
Keybinds
PlayerState
The persistant state for the video player. This must be created on the UI thread and persist across frames.
SharkPlayer
The video player widget. This is what actually get’s created in the ui function.

Enums§

BackendError
Sizing
Constrain SharkPlayer dimensions. To maintain the aspect ratio, only the width or height can be specified.

Traits§

ControlsIconProvider