use std::fmt;
use std::future::Future;
use std::path::PathBuf;
use std::pin::Pin;
use std::sync::Arc;
use std::time::Duration;
use crate::{Size, Surface};
pub trait Players {
fn open(&self, url: &str) -> Box<dyn MediaPlayer>;
}
pub trait MediaPlayer {
fn play(&self);
fn pause(&self);
fn seek(&self, position: Duration);
fn set_rate(&self, rate: f64);
fn set_volume(&self, volume: f64);
fn set_looping(&self, looping: bool);
fn state(&self) -> PlayerState;
fn changed(&self) -> MediaChangeFuture;
fn set_video_surface(&self, surface: Option<Arc<dyn Surface>>);
fn read_frames(&self) -> Arc<dyn FrameReader>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct PlayerState {
pub status: PlayerStatus,
pub playing: bool,
pub position: Duration,
pub duration: Option<Duration>,
pub size: Option<Size>,
pub ended: bool,
}
impl PlayerState {
pub fn loading() -> PlayerState {
PlayerState {
status: PlayerStatus::Loading,
playing: false,
position: Duration::ZERO,
duration: None,
size: None,
ended: false,
}
}
pub fn failed(reason: impl Into<String>) -> PlayerState {
PlayerState {
status: PlayerStatus::Failed(reason.into()),
..PlayerState::loading()
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PlayerStatus {
Loading,
Ready,
Failed(String),
}
pub trait Cameras {
fn cameras(&self) -> Vec<Camera>;
fn open_session(&self, camera: &Camera) -> Box<dyn CaptureSession>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Camera {
pub id: CameraId,
pub name: String,
pub facing: CameraFacing,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CameraId(pub String);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CameraFacing {
Front,
Back,
External,
}
pub trait CaptureSession {
fn start(&self);
fn stop(&self);
fn state(&self) -> CameraState;
fn changed(&self) -> MediaChangeFuture;
fn set_preview_surface(&self, surface: Option<Arc<dyn Surface>>);
fn frame_output(&self) -> Arc<dyn FrameReader>;
fn photo_output(&self) -> Box<dyn PhotoOutput>;
fn movie_output(&self, options: MovieOptions) -> Box<dyn MovieOutput>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct CameraState {
pub status: CameraStatus,
pub size: Option<Size>,
}
impl CameraState {
pub fn stopped() -> CameraState {
CameraState {
status: CameraStatus::Stopped,
size: None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CameraStatus {
Stopped,
Starting,
Running,
Denied,
Failed(String),
}
pub trait PhotoOutput {
fn capture(&self) -> PhotoFuture;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Photo {
pub bytes: Vec<u8>,
pub mime_type: String,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct MovieOptions {
pub sound: bool,
}
pub trait MovieOutput {
fn start(&self, path: PathBuf) -> RecordingFuture;
fn stop(&self);
}
pub trait FrameReader: Send + Sync {
fn newest(&self) -> Option<PixelBuffer>;
}
#[cfg(target_vendor = "apple")]
pub type PixelBuffer = objc2_core_foundation::CFRetained<objc2_core_video::CVPixelBuffer>;
#[cfg(not(target_vendor = "apple"))]
pub enum PixelBuffer {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MediaError {
NotRunning,
Failed(String),
}
impl fmt::Display for MediaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MediaError::NotRunning => f.write_str("the camera session does not run"),
MediaError::Failed(reason) => write!(f, "the camera failed: {reason}"),
}
}
}
impl std::error::Error for MediaError {}
pub type MediaChangeFuture = Pin<Box<dyn Future<Output = ()>>>;
pub type PhotoFuture = Pin<Box<dyn Future<Output = Result<Photo, MediaError>>>>;
pub type RecordingFuture = Pin<Box<dyn Future<Output = Result<(), MediaError>>>>;