Fixes for seek
This commit is contained in:
parent
d39c10b946
commit
e11c9dee55
1 changed files with 67 additions and 54 deletions
121
src/player.rs
121
src/player.rs
|
|
@ -259,6 +259,7 @@ fn ffmpeg_thread<P: AsRef<Path>>(
|
|||
.best(Type::Audio)
|
||||
.ok_or(ffmpeg::Error::StreamNotFound)?;
|
||||
let audio_stream_index = audio_stream.index();
|
||||
let audio_time_base = f64::from(audio_stream.time_base());
|
||||
|
||||
let audio_context_decoder =
|
||||
ffmpeg::codec::context::Context::from_parameters(audio_stream.parameters())?;
|
||||
|
|
@ -281,72 +282,77 @@ fn ffmpeg_thread<P: AsRef<Path>>(
|
|||
audio_config.sample_rate().0,
|
||||
)?;
|
||||
|
||||
let mut start_time_opt = None;
|
||||
let mut start_sample = 0;
|
||||
let mut end_sample = 0;
|
||||
let mut sync_sample = 0;
|
||||
let mut current_sample = 0;
|
||||
let min_sleep = Duration::from_millis(1);
|
||||
let min_skip = Duration::from_millis(1);
|
||||
let mut receive_and_process_decoded_audio_frames =
|
||||
|decoder: &mut ffmpeg::decoder::Audio| -> Result<(), ffmpeg::Error> {
|
||||
let mut decoded = Audio::empty();
|
||||
let mut resampled = Audio::empty();
|
||||
while decoder.receive_frame(&mut decoded).is_ok() {
|
||||
audio_resampler.run(&decoded, &mut resampled)?;
|
||||
let mut receive_and_process_decoded_audio_frames = |decoder: &mut ffmpeg::decoder::Audio,
|
||||
sync_time_opt: &mut Option<Instant>|
|
||||
-> Result<(), ffmpeg::Error> {
|
||||
let mut decoded = Audio::empty();
|
||||
let mut resampled = Audio::empty();
|
||||
while decoder.receive_frame(&mut decoded).is_ok() {
|
||||
audio_resampler.run(&decoded, &mut resampled)?;
|
||||
{
|
||||
// plane method doesn't work with packed samples, so do it manually
|
||||
let plane = unsafe {
|
||||
slice::from_raw_parts(
|
||||
(*resampled.as_ptr()).data[0] as *const f32,
|
||||
resampled.samples() * resampled.channels() as usize,
|
||||
)
|
||||
};
|
||||
{
|
||||
// plane method doesn't work with packed samples, so do it manually
|
||||
let plane = unsafe {
|
||||
slice::from_raw_parts(
|
||||
(*resampled.as_ptr()).data[0] as *const f32,
|
||||
resampled.samples() * resampled.channels() as usize,
|
||||
)
|
||||
};
|
||||
{
|
||||
let mut audio_queue = audio_queue_lock.lock().unwrap();
|
||||
audio_queue.extend(plane);
|
||||
}
|
||||
}
|
||||
|
||||
end_sample += decoded.samples();
|
||||
if start_time_opt.is_none() {
|
||||
start_time_opt = Some(Instant::now());
|
||||
start_sample = end_sample;
|
||||
let mut audio_queue = audio_queue_lock.lock().unwrap();
|
||||
audio_queue.extend(plane);
|
||||
}
|
||||
}
|
||||
|
||||
// Sync with audio
|
||||
if let Some(start_time) = &start_time_opt {
|
||||
let samples = end_sample - start_sample;
|
||||
let expected_float = (samples as f64) / f64::from(decoder.rate());
|
||||
let expected = Duration::from_secs_f64(expected_float);
|
||||
let actual = start_time.elapsed();
|
||||
if expected > actual {
|
||||
let sleep = expected - actual;
|
||||
if sleep > min_sleep {
|
||||
// We leave min_sleep of buffer room
|
||||
thread::sleep(sleep - min_sleep);
|
||||
}
|
||||
} else {
|
||||
let skip = actual - expected;
|
||||
if skip > min_skip {
|
||||
//TODO: handle frame skipping
|
||||
}
|
||||
current_sample += decoded.samples();
|
||||
if sync_time_opt.is_none() {
|
||||
*sync_time_opt = Some(Instant::now());
|
||||
sync_sample = current_sample;
|
||||
}
|
||||
}
|
||||
|
||||
// Sync with audio
|
||||
if let Some(sync_time) = &sync_time_opt {
|
||||
let samples = current_sample - sync_sample;
|
||||
let expected_float = (samples as f64) / f64::from(decoder.rate());
|
||||
let expected = Duration::from_secs_f64(expected_float);
|
||||
let actual = sync_time.elapsed();
|
||||
if expected > actual {
|
||||
let sleep = expected - actual;
|
||||
if sleep > min_sleep {
|
||||
// We leave min_sleep of buffer room
|
||||
thread::sleep(sleep - min_sleep);
|
||||
}
|
||||
} else {
|
||||
let skip = actual - expected;
|
||||
if skip > min_skip {
|
||||
//TODO: handle frame skipping
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let mut sync_time_opt = None;
|
||||
let mut seconds_opt = None;
|
||||
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)?;
|
||||
receive_and_process_decoded_audio_frames(
|
||||
&mut audio_decoder,
|
||||
&mut sync_time_opt,
|
||||
)?;
|
||||
if let Some(pts) = packet.pts() {
|
||||
seconds_opt = Some(pts as f64 * audio_time_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(error::Error::Eof) => break,
|
||||
|
|
@ -356,16 +362,23 @@ fn ffmpeg_thread<P: AsRef<Path>>(
|
|||
while let Ok(message) = player_rx.try_recv() {
|
||||
match message {
|
||||
PlayerMessage::SeekRelative(seek_seconds) => {
|
||||
if let Some(pts) = pts_opt {
|
||||
if let Some(seconds) = seconds_opt {
|
||||
//TODO: use time base instead of hardcoded values
|
||||
let timestamp = (pts + (seek_seconds * 1000.0) as i64) * 1000;
|
||||
let timestamp = ((seconds + seek_seconds) * 1000000.0) as i64;
|
||||
if seek_seconds.is_sign_negative() {
|
||||
println!("backwards {} = {}", seek_seconds, timestamp);
|
||||
println!(
|
||||
"backwards {} from {} = {}",
|
||||
seek_seconds, seconds, timestamp
|
||||
);
|
||||
ictx.seek(timestamp, ..timestamp)?;
|
||||
} else {
|
||||
println!("forwards {} = {}", seek_seconds, timestamp);
|
||||
println!("forwards {} from {} = {}", seek_seconds, seconds, timestamp);
|
||||
ictx.seek(timestamp, timestamp..)?;
|
||||
}
|
||||
|
||||
//TODO: improve sync when seeking
|
||||
// Clear audio sync time
|
||||
sync_time_opt = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -373,7 +386,7 @@ fn ffmpeg_thread<P: AsRef<Path>>(
|
|||
}
|
||||
|
||||
audio_decoder.send_eof()?;
|
||||
receive_and_process_decoded_audio_frames(&mut audio_decoder)?;
|
||||
receive_and_process_decoded_audio_frames(&mut audio_decoder, &mut sync_time_opt)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue