Files
OpenSceneGraph/src/osgPlugins/ffmpeg/FFmpegClocks.cpp
2012-03-21 17:36:20 +00:00

257 lines
4.7 KiB
C++

#include "FFmpegClocks.hpp"
#include <cmath>
#include <algorithm>
// DEBUG
//#include <iostream>
namespace osgFFmpeg {
namespace
{
const double AV_SYNC_THRESHOLD = 0.01;
const double AV_NOSYNC_THRESHOLD = 10.0;
inline double clamp(const double value, const double min, const double max)
{
return (std::min)((std::max)(value, min), max);
}
}
FFmpegClocks::FFmpegClocks() :
m_video_clock(0),
m_start_time(0),
m_pause_time(0),
m_seek_time(0),
m_last_frame_delay(0.040),
m_last_frame_pts(0),
m_last_actual_delay(0),
m_frame_time(0),
m_audio_buffer_end_pts(0),
m_audio_delay(0.0),
m_audio_disabled(false),
m_paused(false),
m_last_current_time(0.0)
{
}
void FFmpegClocks::reset(const double start_time)
{
ScopedLock lock(m_mutex);
m_video_clock = start_time;
m_start_time = start_time;
m_last_frame_delay = 0.040;
m_last_frame_pts = start_time - m_last_frame_delay;
m_frame_time = start_time;
m_pause_time = 0;
m_seek_time = 0;
m_audio_buffer_end_pts = start_time;
m_audio_timer.setStartTick();
}
void FFmpegClocks::pause(bool pause)
{
if(pause)
m_paused = true;
else
{
m_paused = false;
if(!m_audio_disabled) m_audio_timer.setStartTick();
}
}
void FFmpegClocks::rewind()
{
ScopedLock lock(m_mutex);
m_pause_time = 0;
m_seek_time = 0;
m_audio_buffer_end_pts = m_start_time;
m_audio_timer.setStartTick();
m_last_frame_delay = 0.040;
m_frame_time = m_start_time;
if (m_audio_disabled)
return;
m_video_clock = m_start_time;
}
void FFmpegClocks::seek(double seek_time)
{
ScopedLock lock(m_mutex);
m_video_clock = seek_time;
m_last_frame_delay = 0.040;
m_frame_time = seek_time;
}
void FFmpegClocks::audioSetBufferEndPts(const double pts)
{
ScopedLock lock(m_mutex);
m_audio_buffer_end_pts = pts;
m_audio_timer.setStartTick();
}
void FFmpegClocks::audioAdjustBufferEndPts(double increment)
{
ScopedLock lock(m_mutex);
m_audio_buffer_end_pts += increment;
m_audio_timer.setStartTick();
}
void FFmpegClocks::audioSetDelay(const double delay)
{
m_audio_delay = delay;
}
void FFmpegClocks::audioDisable()
{
ScopedLock lock(m_mutex);
m_audio_disabled = true;
}
double FFmpegClocks::videoSynchClock(const AVFrame * const frame, const double time_base, double pts)
{
if (pts != 0)
{
// If we have a PTS, set the video clock to it.
m_video_clock = pts;
}
else
{
// Else, if we don't, use the video clock value.
pts = m_video_clock;
}
// Update the video clock to take into account the frame delay
double frame_delay = time_base;
frame_delay += frame->repeat_pict * (frame_delay * 0.5);
m_video_clock += frame_delay;
return pts;
}
double FFmpegClocks::videoRefreshSchedule(const double pts)
{
ScopedLock lock(m_mutex);
// DEBUG
//std::cerr << "ftime / dpts / delay / audio_time / adelay: ";
double delay = pts - m_last_frame_pts;
//std::cerr << m_frame_time << " / ";
//std::cerr << delay << " / ";
// If incorrect delay, use previous one
if (delay <= 0.0 || delay >= 1.0)
{
delay = m_last_frame_delay;
if(!m_audio_disabled) m_frame_time = pts - delay;
}
// Save for next time
m_last_frame_delay = delay;
m_last_frame_pts = pts;
// Update the delay to synch to the audio stream
// Ideally the frame time should be incremented after the actual delay is computed.
// But because of the sound latency, it seems better to keep some latency in the video too.
m_frame_time += delay;
const double audio_time = getAudioTime();
const double actual_delay = clamp(m_frame_time - audio_time, -0.5*delay, 2.5*delay);
//m_frame_time += delay;
// DEBUG
//std::cerr << delay << " / ";
//std::cerr << audio_time << " / ";
//std::cerr << actual_delay << std::endl;
m_last_actual_delay = actual_delay;
return actual_delay;
}
double FFmpegClocks::getStartTime() const
{
return m_start_time;
}
void FFmpegClocks::setPauseTime(double pause_time)
{
m_pause_time += pause_time;
}
void FFmpegClocks::setSeekTime(double seek_time)
{
m_seek_time += getAudioTime() - seek_time;
}
double FFmpegClocks::getAudioTime() const
{
if(m_audio_disabled)
return m_audio_buffer_end_pts + m_audio_timer.time_s() - m_pause_time - m_audio_delay - m_seek_time;
else
return m_audio_buffer_end_pts + m_audio_timer.time_s() - m_audio_delay;
}
double FFmpegClocks::getCurrentTime()
{
if(!m_paused)
m_last_current_time = getAudioTime();
return m_last_current_time;
}
} // namespace osgFFmpeg