Add seek forwards/backwards
This commit is contained in:
parent
48ba7e7278
commit
d39c10b946
3 changed files with 73 additions and 19 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
23
src/main.rs
23
src/main.rs
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue