From 74a9ccb49d80cd38f49a425eaddf8b063c3d601b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 9 Aug 2010 17:02:31 +0000 Subject: [PATCH] From David Fries, merge from a series of related submission emails: "enable thread locking in libavcodec This is required for a multithreaded application using ffmpeg from another thread." "Prevent the audio from videos from hanging on exit if they are paused. The video decoder already has similar logic." "Add a way to retrieve the creation time for MPEG-4 files." "fmpeg, improve wait for close logic Both audio and video destructors have been succesfully using the logic, if(isRunning()) { m_exit = true; join(); } since it was introduced, but the close routines are using, m_exit = true; if(isRunning() && waitForThreadToExit) { while(isRunning()) { OpenThreads::Thread::YieldCurrentThread(); } } which not only is it doing an unnecessary busy wait, but it doesn't guaranteed that the other thread has terminated, just that it has progressed far enough that OpenThreads has set the thread status as not running. Like the destructor set the m_exit after checking isRunning() to avoid the race condition of not getting to join() because the thread was running, but isRunning() returns false. Now that FFmpeg*close is fixed, call it from the destructor as well to have that code in only one location." --- include/osg/ImageStream | 2 +- src/osgPlugins/ffmpeg/FFmpegDecoder.hpp | 8 +++++ src/osgPlugins/ffmpeg/FFmpegDecoderAudio.cpp | 20 ++++-------- src/osgPlugins/ffmpeg/FFmpegDecoderVideo.cpp | 19 +++-------- src/osgPlugins/ffmpeg/FFmpegImageStream.cpp | 5 +++ src/osgPlugins/ffmpeg/FFmpegImageStream.hpp | 1 + src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp | 33 ++++++++++++++++++++ 7 files changed, 59 insertions(+), 29 deletions(-) diff --git a/include/osg/ImageStream b/include/osg/ImageStream index 2749cd296..4b4a6d593 100644 --- a/include/osg/ImageStream +++ b/include/osg/ImageStream @@ -76,7 +76,7 @@ class OSG_EXPORT ImageStream : public Image LoopingMode getLoopingMode() const { return _loopingMode; } - + virtual double getCreationTime() const { return HUGE_VAL; } virtual double getLength() const { return 0.0; } virtual double getFrameRate() const { return 0.0; } diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp b/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp index 6176dccfc..a783f0161 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp @@ -26,6 +26,8 @@ class FormatContextPtr T* get() { return _ptr; } + operator bool() const { return _ptr != 0; } + T * operator-> () const // never throws { return _ptr; @@ -74,6 +76,7 @@ public: void loop(bool loop); bool loop() const; + double creation_time() const; double duration() const; double reference(); @@ -144,6 +147,11 @@ inline bool FFmpegDecoder::loop() const return m_loop; } +inline double FFmpegDecoder::creation_time() const +{ + if(m_format_context) return m_format_context->timestamp; + else return HUGE_VAL; +} inline double FFmpegDecoder::duration() const { diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoderAudio.cpp b/src/osgPlugins/ffmpeg/FFmpegDecoderAudio.cpp index 769bda16a..f7020fb8f 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoderAudio.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoderAudio.cpp @@ -54,15 +54,7 @@ FFmpegDecoderAudio::FFmpegDecoderAudio(PacketQueue & packets, FFmpegClocks & clo FFmpegDecoderAudio::~FFmpegDecoderAudio() { - if (isRunning()) - { - m_exit = true; -#if 0 - while(isRunning()) { OpenThreads::YieldCurrentThread(); } -#else - join(); -#endif - } + this->close(true); } @@ -123,11 +115,11 @@ void FFmpegDecoderAudio::pause(bool pause) void FFmpegDecoderAudio::close(bool waitForThreadToExit) { - m_exit = true; - - if (isRunning() && waitForThreadToExit) + if (isRunning()) { - while(isRunning()) { OpenThreads::Thread::YieldCurrentThread(); } + m_exit = true; + if (waitForThreadToExit) + join(); } } @@ -238,7 +230,7 @@ void FFmpegDecoderAudio::decodeLoop() m_clocks.pause(true); m_pause_timer.setStartTick(); - while(m_paused) + while(m_paused && !m_exit) { microSleep(10000); } diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoderVideo.cpp b/src/osgPlugins/ffmpeg/FFmpegDecoderVideo.cpp index eed5825dd..e2bc11e3c 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoderVideo.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoderVideo.cpp @@ -57,17 +57,8 @@ FFmpegDecoderVideo::~FFmpegDecoderVideo() { OSG_INFO<<"Destructing FFmpegDecoderVideo..."<close(true); - if (isRunning()) - { - m_exit = true; -#if 0 - while(isRunning()) { OpenThreads::YieldCurrentThread(); } -#else - join(); -#endif - } - #ifdef USE_SWSCALE if (m_swscale_ctx) { @@ -132,11 +123,11 @@ void FFmpegDecoderVideo::open(AVStream * const stream) void FFmpegDecoderVideo::close(bool waitForThreadToExit) { - m_exit = true; - - if (isRunning() && waitForThreadToExit) + if (isRunning()) { - while(isRunning()) { OpenThreads::Thread::YieldCurrentThread(); } + m_exit = true; + if (waitForThreadToExit) + join(); } } diff --git a/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp b/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp index e14fbd97a..bd25ef8bd 100644 --- a/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp @@ -162,6 +162,11 @@ float FFmpegImageStream::getVolume() const return m_decoder->audio_decoder().getVolume(); } +double FFmpegImageStream::getCreationTime() const +{ + return m_decoder->creation_time(); +} + double FFmpegImageStream::getLength() const { return m_decoder->duration(); diff --git a/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp b/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp index 033a892db..4395a58df 100644 --- a/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp +++ b/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp @@ -36,6 +36,7 @@ namespace osgFFmpeg virtual void setVolume(float volume); virtual float getVolume() const; + virtual double getCreationTime() const; virtual double getLength() const; virtual double getReferenceTime () const; virtual double getFrameRate() const; diff --git a/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp b/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp index fb1a0ddc8..28eb31ed0 100644 --- a/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp +++ b/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp @@ -45,6 +45,9 @@ public: supportsExtension("sav", "MPEG-4"); supportsExtension("3gp", "MPEG-4"); supportsExtension("sdp", "MPEG-4"); + + // enable thread locking + av_lockmgr_register(&lockMgr); // Register all FFmpeg formats/codecs av_register_all(); @@ -97,6 +100,36 @@ public: private: + static int lockMgr(void **mutex, enum AVLockOp op) + { + // returns are 0 success + OpenThreads::Mutex **m=(OpenThreads::Mutex**)mutex; + if (op==AV_LOCK_CREATE) + { + *m=new OpenThreads::Mutex; + return !*m; + } + else if (op==AV_LOCK_DESTROY) + { + delete *m; + return 0; + } + else if (op==AV_LOCK_OBTAIN) + { + (*m)->lock(); + return 0; + } + else if (op==AV_LOCK_RELEASE) + { + (*m)->unlock(); + return 0; + } + else + { + return -1; + } + } + };