Fixes for seek

This commit is contained in:
Jeremy Soller 2024-01-24 21:27:10 -07:00
parent d39c10b946
commit e11c9dee55
No known key found for this signature in database
GPG key ID: DCFCA852D3906975

View file

@ -259,6 +259,7 @@ fn ffmpeg_thread<P: AsRef<Path>>(
.best(Type::Audio) .best(Type::Audio)
.ok_or(ffmpeg::Error::StreamNotFound)?; .ok_or(ffmpeg::Error::StreamNotFound)?;
let audio_stream_index = audio_stream.index(); let audio_stream_index = audio_stream.index();
let audio_time_base = f64::from(audio_stream.time_base());
let audio_context_decoder = let audio_context_decoder =
ffmpeg::codec::context::Context::from_parameters(audio_stream.parameters())?; ffmpeg::codec::context::Context::from_parameters(audio_stream.parameters())?;
@ -281,72 +282,77 @@ fn ffmpeg_thread<P: AsRef<Path>>(
audio_config.sample_rate().0, audio_config.sample_rate().0,
)?; )?;
let mut start_time_opt = None; let mut sync_sample = 0;
let mut start_sample = 0; let mut current_sample = 0;
let mut end_sample = 0;
let min_sleep = Duration::from_millis(1); let min_sleep = Duration::from_millis(1);
let min_skip = Duration::from_millis(1); let min_skip = Duration::from_millis(1);
let mut receive_and_process_decoded_audio_frames = let mut receive_and_process_decoded_audio_frames = |decoder: &mut ffmpeg::decoder::Audio,
|decoder: &mut ffmpeg::decoder::Audio| -> Result<(), ffmpeg::Error> { sync_time_opt: &mut Option<Instant>|
let mut decoded = Audio::empty(); -> Result<(), ffmpeg::Error> {
let mut resampled = Audio::empty(); let mut decoded = Audio::empty();
while decoder.receive_frame(&mut decoded).is_ok() { let mut resampled = Audio::empty();
audio_resampler.run(&decoded, &mut resampled)?; 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 mut audio_queue = audio_queue_lock.lock().unwrap();
let plane = unsafe { audio_queue.extend(plane);
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;
} }
} }
// Sync with audio current_sample += decoded.samples();
if let Some(start_time) = &start_time_opt { if sync_time_opt.is_none() {
let samples = end_sample - start_sample; *sync_time_opt = Some(Instant::now());
let expected_float = (samples as f64) / f64::from(decoder.rate()); sync_sample = current_sample;
let expected = Duration::from_secs_f64(expected_float); }
let actual = start_time.elapsed(); }
if expected > actual {
let sleep = expected - actual; // Sync with audio
if sleep > min_sleep { if let Some(sync_time) = &sync_time_opt {
// We leave min_sleep of buffer room let samples = current_sample - sync_sample;
thread::sleep(sleep - min_sleep); let expected_float = (samples as f64) / f64::from(decoder.rate());
} let expected = Duration::from_secs_f64(expected_float);
} else { let actual = sync_time.elapsed();
let skip = actual - expected; if expected > actual {
if skip > min_skip { let sleep = expected - actual;
//TODO: handle frame skipping 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 { loop {
let mut pts_opt = None;
let mut packet = Packet::empty(); let mut packet = Packet::empty();
match packet.read(&mut ictx) { match packet.read(&mut ictx) {
Ok(()) => { Ok(()) => {
pts_opt = packet.pts();
if packet.stream() == video_stream_index { if packet.stream() == video_stream_index {
video_packet_tx.send(packet).unwrap(); video_packet_tx.send(packet).unwrap();
} else if packet.stream() == audio_stream_index { } else if packet.stream() == audio_stream_index {
audio_decoder.send_packet(&packet)?; 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, Err(error::Error::Eof) => break,
@ -356,16 +362,23 @@ fn ffmpeg_thread<P: AsRef<Path>>(
while let Ok(message) = player_rx.try_recv() { while let Ok(message) = player_rx.try_recv() {
match message { match message {
PlayerMessage::SeekRelative(seek_seconds) => { PlayerMessage::SeekRelative(seek_seconds) => {
if let Some(pts) = pts_opt { if let Some(seconds) = seconds_opt {
//TODO: use time base instead of hardcoded values //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() { if seek_seconds.is_sign_negative() {
println!("backwards {} = {}", seek_seconds, timestamp); println!(
"backwards {} from {} = {}",
seek_seconds, seconds, timestamp
);
ictx.seek(timestamp, ..timestamp)?; ictx.seek(timestamp, ..timestamp)?;
} else { } else {
println!("forwards {} = {}", seek_seconds, timestamp); println!("forwards {} from {} = {}", seek_seconds, seconds, timestamp);
ictx.seek(timestamp, 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()?; 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(()) Ok(())
} }