From Julen Garcia,"I've been lately working also with the ffmpeg plugin and I implemented pause(), seek() and getReferenceTime(). I think that I have solved the internal clock issues (maybe not in the most elegant way :?"

This commit is contained in:
Robert Osfield
2009-12-02 18:58:45 +00:00
parent 11abf29c14
commit 8080f46444
10 changed files with 138 additions and 47 deletions

View File

@@ -30,6 +30,8 @@ namespace
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),
@@ -37,7 +39,9 @@ FFmpegClocks::FFmpegClocks() :
m_audio_buffer_end_pts(0),
m_audio_delay(0.0),
m_audio_disabled(false),
m_rewind(false)
m_rewind(false),
m_paused(false),
m_last_current_time(0.0)
{
}
@@ -59,6 +63,14 @@ void FFmpegClocks::reset(const double start_time)
m_audio_timer.setStartTick();
}
void FFmpegClocks::pause(bool pause)
{
if(pause)
m_paused = true;
else
m_paused = false;
}
void FFmpegClocks::rewindAudio()
@@ -205,13 +217,30 @@ double FFmpegClocks::getStartTime() const
return m_start_time;
}
double FFmpegClocks::getAudioTime() const
void FFmpegClocks::setPauseTime(double pause_time)
{
return m_audio_buffer_end_pts + m_audio_timer.time_s() - m_audio_delay;
m_pause_time += pause_time;
}
void FFmpegClocks::setSeekTime(double seek_time)
{
m_seek_time = getAudioTime() - seek_time;
}
double FFmpegClocks::getAudioTime() const
{
return m_audio_buffer_end_pts + m_audio_timer.time_s() - m_pause_time - m_audio_delay;
}
double FFmpegClocks::getCurrentTime()
{
if(!m_paused)
m_last_current_time = getAudioTime() - m_seek_time; // synced with audio
return m_last_current_time;
}
} // namespace osgFFmpeg

View File

@@ -22,6 +22,7 @@ public:
FFmpegClocks();
void reset(double start_time);
void pause(bool pause);
void rewindAudio();
void rewindVideo();
@@ -35,6 +36,9 @@ public:
double videoRefreshSchedule(double pts);
double getStartTime() const;
double getCurrentTime();
void setPauseTime(double pause_time);
void setSeekTime(double seek_time);
private:
@@ -49,15 +53,20 @@ private:
double m_video_clock;
double m_start_time;
double m_pause_time;
double m_seek_time;
double m_last_frame_delay;
double m_last_frame_pts;
double m_last_actual_delay;
double m_frame_time;
double m_audio_buffer_end_pts;
double m_audio_delay;
Timer m_audio_timer;
bool m_audio_disabled;
bool m_rewind;
Timer m_audio_timer;
bool m_audio_disabled;
bool m_rewind;
bool m_paused;
double m_last_current_time;
};

View File

@@ -213,15 +213,6 @@ void FFmpegDecoder::pause()
m_state = PAUSE;
}
void FFmpegDecoder::resume()
{
m_pending_packet.clear();
flushAudioQueue();
flushVideoQueue();
m_state = NORMAL;
}
void FFmpegDecoder::findAudioStream()
{
for (unsigned int i = 0; i < m_format_context->nb_streams; ++i)
@@ -294,7 +285,10 @@ bool FFmpegDecoder::readNextPacketNormal()
{
// If we reach the end of the stream, change the decoder state
if (loop())
{
m_clocks.reset(m_start);
rewindButDontFlushQueues();
}
else
m_state = END_OF_STREAM;
@@ -393,6 +387,8 @@ void FFmpegDecoder::seekButDontFlushQueues(double time)
const int64_t pos = int64_t(m_clocks.getStartTime()+time * double(AV_TIME_BASE));
const int64_t seek_target = av_rescale_q(pos, AvTimeBaseQ, m_video_stream->time_base);
m_clocks.setSeekTime(time);
if (av_seek_frame(m_format_context.get(), m_video_index, seek_target, 0/*AVSEEK_FLAG_BYTE |*/ /*AVSEEK_FLAG_BACKWARD*/) < 0)
throw std::runtime_error("av_seek_frame failed()");

View File

@@ -70,12 +70,12 @@ public:
void rewind();
void seek(double time);
void pause();
void resume();
void loop(bool loop);
bool loop() const;
double duration() const;
double reference();
FFmpegDecoderAudio & audio_decoder();
FFmpegDecoderVideo & video_decoder();
@@ -108,24 +108,24 @@ protected:
void seekButDontFlushQueues(double time);
FormatContextPtr m_format_context;
AVStream * m_audio_stream;
AVStream * m_video_stream;
AVStream * m_audio_stream;
AVStream * m_video_stream;
int m_audio_index;
int m_video_index;
FFmpegClocks m_clocks;
FFmpegPacket m_pending_packet;
PacketQueue m_audio_queue;
PacketQueue m_video_queue;
PacketQueue m_audio_queue;
PacketQueue m_video_queue;
FFmpegDecoderAudio m_audio_decoder;
FFmpegDecoderVideo m_video_decoder;
FFmpegDecoderAudio m_audio_decoder;
FFmpegDecoderVideo m_video_decoder;
double m_duration;
double m_start;
double m_duration;
double m_start;
State m_state;
State m_state;
bool m_loop;
};
@@ -150,6 +150,11 @@ inline double FFmpegDecoder::duration() const
return double(m_format_context->duration) / AV_TIME_BASE;
}
inline double FFmpegDecoder::reference()
{
return m_clocks.getCurrentTime();
}
inline FFmpegDecoderAudio & FFmpegDecoder::audio_decoder()
{

View File

@@ -25,6 +25,7 @@ FFmpegDecoderAudio::FFmpegDecoderAudio(PacketQueue & packets, FFmpegClocks & clo
m_audio_buf_size(0),
m_audio_buf_index(0),
m_end_of_stream(false),
m_paused(true),
m_exit(false)
{
@@ -88,6 +89,13 @@ void FFmpegDecoderAudio::open(AVStream * const stream)
}
}
void FFmpegDecoderAudio::pause(bool pause)
{
if(pause)
m_paused = true;
else
m_paused = false;
}
void FFmpegDecoderAudio::close(bool waitForThreadToExit)
{
@@ -184,6 +192,21 @@ void FFmpegDecoderAudio::decodeLoop()
while (! m_exit)
{
if(m_paused)
{
m_clocks.pause(true);
m_pause_timer.setStartTick();
while(m_paused)
{
microSleep(10000);
}
m_clocks.setPauseTime(m_pause_timer.time_s());
m_clocks.pause(false);
}
// If skipping audio, make sure the audio stream is still consumed.
if (skip_audio)
{
@@ -193,7 +216,6 @@ void FFmpegDecoderAudio::decodeLoop()
if (packet.valid())
packet.clear();
}
// Else, just idle in this thread.
// Note: If m_audio_sink has an audio callback, this thread will still be awaken
// from time to time to refill the audio buffer.

View File

@@ -4,6 +4,8 @@
#include <OpenThreads/Thread>
#include <osg/Timer>
#include "FFmpegClocks.hpp"
#include "FFmpegPacket.hpp"
@@ -29,6 +31,7 @@ public:
~FFmpegDecoderAudio();
void open(AVStream * stream);
void pause(bool pause);
void close(bool waitForThreadToExit);
virtual void run();
@@ -51,26 +54,29 @@ private:
size_t decodeFrame(void * buffer, size_t size);
PacketQueue & m_packets;
FFmpegClocks & m_clocks;
AVStream * m_stream;
AVCodecContext * m_context;
FFmpegPacket m_packet;
const uint8_t * m_packet_data;
int m_bytes_remaining;
PacketQueue & m_packets;
FFmpegClocks & m_clocks;
AVStream * m_stream;
AVCodecContext * m_context;
FFmpegPacket m_packet;
const uint8_t * m_packet_data;
int m_bytes_remaining;
Buffer m_audio_buffer;
size_t m_audio_buf_size;
size_t m_audio_buf_index;
Buffer m_audio_buffer;
size_t m_audio_buf_size;
size_t m_audio_buf_index;
int m_frequency;
int m_nb_channels;
osg::AudioStream::SampleFormat m_sample_format;
int m_frequency;
int m_nb_channels;
osg::AudioStream::SampleFormat m_sample_format;
SinkPtr m_audio_sink;
SinkPtr m_audio_sink;
bool m_end_of_stream;
volatile bool m_exit;
osg::Timer m_pause_timer;
bool m_end_of_stream;
bool m_paused;
volatile bool m_exit;
};

View File

@@ -20,6 +20,7 @@ FFmpegDecoderVideo::FFmpegDecoderVideo(PacketQueue & packets, FFmpegClocks & clo
m_writeBuffer(0),
m_user_data(0),
m_publish_func(0),
m_paused(true),
m_exit(false)
#ifdef USE_SWSCALE
,m_swscale_ctx(0)
@@ -117,6 +118,13 @@ void FFmpegDecoderVideo::close(bool waitForThreadToExit)
}
}
void FFmpegDecoderVideo::pause(bool pause)
{
if(pause)
m_paused = true;
else
m_paused = false;
}
void FFmpegDecoderVideo::run()
{
@@ -194,6 +202,11 @@ void FFmpegDecoderVideo::decodeLoop()
}
}
while(m_paused && !m_exit)
{
microSleep(10000);
}
// Get the next packet
pts = 0;

View File

@@ -65,6 +65,7 @@ public:
~FFmpegDecoderVideo();
void open(AVStream * stream);
void pause(bool pause);
void close(bool waitForThreadToExit);
virtual void run();
@@ -120,6 +121,7 @@ private:
size_t m_next_frame_index;
bool m_alpha_channel;
bool m_paused;
volatile bool m_exit;
#ifdef USE_SWSCALE

View File

@@ -159,6 +159,12 @@ double FFmpegImageStream::getLength() const
}
double FFmpegImageStream::getReferenceTime () const
{
return m_decoder->reference();
}
double FFmpegImageStream::getFrameRate() const
{
@@ -264,7 +270,8 @@ void FFmpegImageStream::cmdPlay()
if (! m_decoder->video_decoder().isRunning())
m_decoder->video_decoder().start();
m_decoder->resume();
m_decoder->video_decoder().pause(false);
m_decoder->audio_decoder().pause(false);
}
_status = PLAYING;
@@ -276,7 +283,8 @@ void FFmpegImageStream::cmdPause()
{
if (_status == PLAYING)
{
m_decoder->pause();
m_decoder->video_decoder().pause(true);
m_decoder->audio_decoder().pause(true);
}
_status = PAUSED;

View File

@@ -34,6 +34,7 @@ namespace osgFFmpeg
virtual void quit(bool waitForThreadToExit = true);
virtual double getLength() const;
virtual double getReferenceTime () const;
virtual double getFrameRate() const;
virtual bool isImageTranslucent() const;
@@ -71,7 +72,7 @@ namespace osgFFmpeg
Mutex m_mutex;
Condition m_frame_published_cond;
bool m_frame_published_flag;
bool m_frame_published_flag;
double m_seek_time;
};