From Rafa Gaitan, "Current ffmpeg plugin didn't support pause and seek, I have added this
functionality and I also modified osgmovie example to support "seek"." Note from Robert Osfield, changes osgmovie to use '>' for the seek as '+' was already used in a separate submission that had been merged.
This commit is contained in:
@@ -118,6 +118,7 @@ protected:
|
||||
|
||||
bool _trackMouse;
|
||||
ImageStreamList _imageStreamList;
|
||||
unsigned int _seekIncr;
|
||||
|
||||
};
|
||||
|
||||
@@ -237,6 +238,23 @@ bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIAction
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()=='>')
|
||||
{
|
||||
for(ImageStreamList::iterator itr=_imageStreamList.begin();
|
||||
itr!=_imageStreamList.end();
|
||||
++itr)
|
||||
{
|
||||
std::cout<<"Seeking"<<std::endl;
|
||||
if(_seekIncr > 3) _seekIncr = 0;
|
||||
double length = (*itr)->getLength();
|
||||
double t_pos = (length/4.0f)*_seekIncr;
|
||||
//(*itr)->rewind();
|
||||
(*itr)->seek(t_pos);
|
||||
(*itr)->play();
|
||||
_seekIncr++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()=='L')
|
||||
{
|
||||
for(ImageStreamList::iterator itr=_imageStreamList.begin();
|
||||
@@ -309,6 +327,7 @@ void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
|
||||
usage.addKeyboardMouseBinding("+","Increase speed of movie");
|
||||
usage.addKeyboardMouseBinding("-","Decrease speed of movie");
|
||||
usage.addKeyboardMouseBinding("o","Display frame rate of movie");
|
||||
usage.addKeyboardMouseBinding(">","Advance the movie using seek");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -166,12 +166,18 @@ bool FFmpegDecoder::readNextPacket()
|
||||
case NORMAL:
|
||||
return readNextPacketNormal();
|
||||
|
||||
case PAUSE:
|
||||
return false;
|
||||
|
||||
case END_OF_STREAM:
|
||||
return readNextPacketEndOfStream();
|
||||
|
||||
case REWINDING:
|
||||
return readNextPacketRewinding();
|
||||
|
||||
case SEEKING:
|
||||
return readNextPacketSeeking();
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
@@ -189,8 +195,32 @@ void FFmpegDecoder::rewind()
|
||||
rewindButDontFlushQueues();
|
||||
}
|
||||
|
||||
void FFmpegDecoder::seek(double time)
|
||||
{
|
||||
m_pending_packet.clear();
|
||||
|
||||
flushAudioQueue();
|
||||
flushVideoQueue();
|
||||
seekButDontFlushQueues(time);
|
||||
}
|
||||
|
||||
void FFmpegDecoder::pause()
|
||||
{
|
||||
m_pending_packet.clear();
|
||||
|
||||
flushAudioQueue();
|
||||
flushVideoQueue();
|
||||
m_state = PAUSE;
|
||||
}
|
||||
|
||||
void FFmpegDecoder::resume()
|
||||
{
|
||||
m_pending_packet.clear();
|
||||
|
||||
flushAudioQueue();
|
||||
flushVideoQueue();
|
||||
m_state = NORMAL;
|
||||
}
|
||||
|
||||
void FFmpegDecoder::findAudioStream()
|
||||
{
|
||||
@@ -346,6 +376,29 @@ void FFmpegDecoder::rewindButDontFlushQueues()
|
||||
m_state = REWINDING;
|
||||
}
|
||||
|
||||
bool FFmpegDecoder::readNextPacketSeeking()
|
||||
{
|
||||
const FFmpegPacket packet(FFmpegPacket::PACKET_FLUSH);
|
||||
|
||||
if (m_audio_queue.timedPush(packet, 10) && m_video_queue.timedPush(packet, 10))
|
||||
m_state = NORMAL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FFmpegDecoder::seekButDontFlushQueues(double time)
|
||||
{
|
||||
const AVRational AvTimeBaseQ = { 1, AV_TIME_BASE }; // = AV_TIME_BASE_Q
|
||||
|
||||
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);
|
||||
|
||||
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()");
|
||||
|
||||
m_state = SEEKING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace osgFFmpeg
|
||||
|
||||
@@ -68,6 +68,9 @@ public:
|
||||
|
||||
bool readNextPacket();
|
||||
void rewind();
|
||||
void seek(double time);
|
||||
void pause();
|
||||
void resume();
|
||||
|
||||
void loop(bool loop);
|
||||
bool loop() const;
|
||||
@@ -84,8 +87,10 @@ protected:
|
||||
enum State
|
||||
{
|
||||
NORMAL,
|
||||
PAUSE,
|
||||
END_OF_STREAM,
|
||||
REWINDING
|
||||
REWINDING,
|
||||
SEEKING
|
||||
};
|
||||
|
||||
typedef BoundedMessageQueue<FFmpegPacket> PacketQueue;
|
||||
@@ -97,7 +102,10 @@ protected:
|
||||
bool readNextPacketNormal();
|
||||
bool readNextPacketEndOfStream();
|
||||
bool readNextPacketRewinding();
|
||||
bool readNextPacketSeeking();
|
||||
bool readNextPacketPause();
|
||||
void rewindButDontFlushQueues();
|
||||
void seekButDontFlushQueues(double time);
|
||||
|
||||
FormatContextPtr m_format_context;
|
||||
AVStream * m_audio_stream;
|
||||
|
||||
@@ -130,6 +130,11 @@ void FFmpegImageStream::rewind()
|
||||
m_commands->push(CMD_REWIND);
|
||||
}
|
||||
|
||||
void FFmpegImageStream::seek(double time) {
|
||||
m_seek_time = time;
|
||||
m_commands->push(CMD_SEEK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FFmpegImageStream::quit(bool waitForThreadToExit)
|
||||
@@ -234,6 +239,10 @@ bool FFmpegImageStream::handleCommand(const Command cmd)
|
||||
cmdRewind();
|
||||
return true;
|
||||
|
||||
case CMD_SEEK:
|
||||
cmdSeek(m_seek_time);
|
||||
return true;
|
||||
|
||||
case CMD_STOP:
|
||||
return false;
|
||||
|
||||
@@ -254,6 +263,8 @@ void FFmpegImageStream::cmdPlay()
|
||||
|
||||
if (! m_decoder->video_decoder().isRunning())
|
||||
m_decoder->video_decoder().start();
|
||||
|
||||
m_decoder->resume();
|
||||
}
|
||||
|
||||
_status = PLAYING;
|
||||
@@ -265,7 +276,7 @@ void FFmpegImageStream::cmdPause()
|
||||
{
|
||||
if (_status == PLAYING)
|
||||
{
|
||||
|
||||
m_decoder->pause();
|
||||
}
|
||||
|
||||
_status = PAUSED;
|
||||
@@ -278,6 +289,10 @@ void FFmpegImageStream::cmdRewind()
|
||||
m_decoder->rewind();
|
||||
}
|
||||
|
||||
void FFmpegImageStream::cmdSeek(double time)
|
||||
{
|
||||
m_decoder->seek(time);
|
||||
}
|
||||
|
||||
|
||||
void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace osgFFmpeg
|
||||
virtual void play();
|
||||
virtual void pause();
|
||||
virtual void rewind();
|
||||
virtual void seek(double time);
|
||||
virtual void quit(bool waitForThreadToExit = true);
|
||||
|
||||
virtual double getLength() const;
|
||||
@@ -44,7 +45,8 @@ namespace osgFFmpeg
|
||||
CMD_PLAY,
|
||||
CMD_PAUSE,
|
||||
CMD_STOP,
|
||||
CMD_REWIND
|
||||
CMD_REWIND,
|
||||
CMD_SEEK
|
||||
};
|
||||
|
||||
typedef MessageQueue<Command> CommandQueue;
|
||||
@@ -60,6 +62,7 @@ namespace osgFFmpeg
|
||||
void cmdPlay();
|
||||
void cmdPause();
|
||||
void cmdRewind();
|
||||
void cmdSeek(double time);
|
||||
|
||||
static void publishNewFrame(const FFmpegDecoderVideo &, void * user_data);
|
||||
|
||||
@@ -69,6 +72,7 @@ namespace osgFFmpeg
|
||||
Mutex m_mutex;
|
||||
Condition m_frame_published_cond;
|
||||
bool m_frame_published_flag;
|
||||
double m_seek_time;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user