From 3ef770a9ff032fcb0d831696183c68380ef98892 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 20 Nov 2009 14:31:11 +0000 Subject: [PATCH] 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. --- examples/osgmovie/osgmovie.cpp | 19 ++++++++ src/osgPlugins/ffmpeg/FFmpegDecoder.cpp | 53 +++++++++++++++++++++ src/osgPlugins/ffmpeg/FFmpegDecoder.hpp | 10 +++- src/osgPlugins/ffmpeg/FFmpegImageStream.cpp | 17 ++++++- src/osgPlugins/ffmpeg/FFmpegImageStream.hpp | 6 ++- 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/examples/osgmovie/osgmovie.cpp b/examples/osgmovie/osgmovie.cpp index dae6bb384..803505f88 100644 --- a/examples/osgmovie/osgmovie.cpp +++ b/examples/osgmovie/osgmovie.cpp @@ -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"< 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"); } diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp b/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp index eef4fb4af..e6119c4b8 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp @@ -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 diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp b/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp index 43bc9475a..b351d2b7a 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp @@ -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 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; diff --git a/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp b/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp index de452c884..ab179a023 100644 --- a/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp @@ -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) diff --git a/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp b/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp index ec2a03ff7..dec9cea1d 100644 --- a/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp +++ b/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp @@ -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 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; }; }