Add seek forwards/backwards

This commit is contained in:
Jeremy Soller 2024-01-24 21:06:07 -07:00
parent 48ba7e7278
commit d39c10b946
No known key found for this signature in database
GPG key ID: DCFCA852D3906975
3 changed files with 73 additions and 19 deletions

View file

@ -42,10 +42,10 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
let mut key_binds = HashMap::new();
macro_rules! bind {
([$($modifier:ident),+ $(,)?], $key_code:ident, $action:ident) => {{
([$($modifier:ident),* $(,)?], $key_code:ident, $action:ident) => {{
key_binds.insert(
KeyBind {
modifiers: vec![$(Modifier::$modifier),+],
modifiers: vec![$(Modifier::$modifier),*],
key_code: KeyCode::$key_code,
},
Action::$action,
@ -54,6 +54,8 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
}
//TODO: key bindings
bind!([], Left, SeekBackward);
bind!([], Right, SeekForward);
key_binds
}

View file

@ -19,20 +19,21 @@ use std::{
env,
path::PathBuf,
process,
sync::{Arc, Mutex},
sync::{mpsc, Arc, Mutex},
time::Instant,
};
use config::{AppTheme, Config, CONFIG_VERSION};
mod config;
mod ffmpeg;
use key_bind::{key_binds, KeyBind};
mod key_bind;
mod localize;
use player::{PlayerMessage, VideoFrame};
mod player;
/// Runs application with these settings
#[rustfmt::skip]
fn main() -> Result<(), Box<dyn std::error::Error>> {
@ -66,7 +67,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
};
let video_frame_lock = ffmpeg::run(path);
let (player_tx, video_frame_lock) = player::run(path);
let mut settings = Settings::default();
settings = settings.theme(config.app_theme.theme());
@ -83,7 +84,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let flags = Flags {
config_handler,
config,
video_frame_lock
player_tx,
video_frame_lock,
};
cosmic::app::run::<App>(settings, flags)?;
@ -93,12 +95,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Action {
Todo,
SeekBackward,
SeekForward,
}
impl Action {
pub fn message(&self) -> Message {
match self {
Self::Todo => Message::Todo,
Self::SeekBackward => Message::Player(PlayerMessage::SeekRelative(-10.0)),
Self::SeekForward => Message::Player(PlayerMessage::SeekRelative(10.0)),
}
}
}
@ -107,7 +113,8 @@ impl Action {
pub struct Flags {
config_handler: Option<cosmic_config::Config>,
config: Config,
video_frame_lock: Arc<Mutex<Option<ffmpeg::VideoFrame>>>,
player_tx: mpsc::Sender<PlayerMessage>,
video_frame_lock: Arc<Mutex<Option<VideoFrame>>>,
}
/// Messages that are used specifically by our [`App`].
@ -117,6 +124,7 @@ pub enum Message {
AppTheme(AppTheme),
Config(Config),
Key(Modifiers, KeyCode),
Player(PlayerMessage),
SystemThemeModeChange(cosmic_theme::ThemeMode),
Tick(Instant),
ToggleContextPage(ContextPage),
@ -281,6 +289,9 @@ impl Application for App {
}
}
}
Message::Player(player_message) => {
self.flags.player_tx.send(player_message).unwrap();
}
Message::SystemThemeModeChange(_theme_mode) => {
return self.update_config();
}

View file

@ -10,10 +10,11 @@ use ffmpeg::{
media::Type,
software::{resampling, scaling},
util::{
channel_layout,
channel_layout, error,
format::sample,
frame::{audio::Audio, video::Video},
},
Packet,
};
use std::{
collections::VecDeque,
@ -25,6 +26,11 @@ use std::{
time::{Duration, Instant},
};
#[derive(Clone, Debug)]
pub enum PlayerMessage {
SeekRelative(f64),
}
pub struct VideoFrame(pub Video);
impl VideoFrame {
@ -143,6 +149,7 @@ where
fn ffmpeg_thread<P: AsRef<Path>>(
path: P,
player_rx: mpsc::Receiver<PlayerMessage>,
video_frame_lock: Arc<Mutex<Option<VideoFrame>>>,
audio_config: cpal::SupportedStreamConfig,
audio_queue_lock: Arc<Mutex<VecDeque<f32>>>,
@ -329,13 +336,39 @@ fn ffmpeg_thread<P: AsRef<Path>>(
Ok(())
};
for (stream, packet) in ictx.packets() {
let start = Instant::now();
if stream.index() == video_stream_index {
video_packet_tx.send(packet).unwrap();
} else if stream.index() == audio_stream_index {
audio_decoder.send_packet(&packet)?;
receive_and_process_decoded_audio_frames(&mut audio_decoder)?;
loop {
let mut pts_opt = None;
let mut packet = Packet::empty();
match packet.read(&mut ictx) {
Ok(()) => {
pts_opt = packet.pts();
if packet.stream() == video_stream_index {
video_packet_tx.send(packet).unwrap();
} else if packet.stream() == audio_stream_index {
audio_decoder.send_packet(&packet)?;
receive_and_process_decoded_audio_frames(&mut audio_decoder)?;
}
}
Err(error::Error::Eof) => break,
Err(_err) => {}
}
while let Ok(message) = player_rx.try_recv() {
match message {
PlayerMessage::SeekRelative(seek_seconds) => {
if let Some(pts) = pts_opt {
//TODO: use time base instead of hardcoded values
let timestamp = (pts + (seek_seconds * 1000.0) as i64) * 1000;
if seek_seconds.is_sign_negative() {
println!("backwards {} = {}", seek_seconds, timestamp);
ictx.seek(timestamp, ..timestamp)?;
} else {
println!("forwards {} = {}", seek_seconds, timestamp);
ictx.seek(timestamp, timestamp..)?;
}
}
}
}
}
}
@ -345,18 +378,26 @@ fn ffmpeg_thread<P: AsRef<Path>>(
Ok(())
}
pub fn run(path: PathBuf) -> Arc<Mutex<Option<VideoFrame>>> {
pub fn run(path: PathBuf) -> (mpsc::Sender<PlayerMessage>, Arc<Mutex<Option<VideoFrame>>>) {
ffmpeg::init().unwrap();
let audio_queue_lock = Arc::new(Mutex::new(VecDeque::new()));
let audio_config = cpal(audio_queue_lock.clone());
let (player_tx, player_rx) = mpsc::channel();
let video_frame_lock = Arc::new(Mutex::new(None));
{
let video_frame_lock = video_frame_lock.clone();
thread::spawn(move || {
ffmpeg_thread(path, video_frame_lock, audio_config, audio_queue_lock).unwrap();
ffmpeg_thread(
path,
player_rx,
video_frame_lock,
audio_config,
audio_queue_lock,
)
.unwrap();
});
}
video_frame_lock
(player_tx, video_frame_lock)
}