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."
This commit is contained in:
Robert Osfield
2010-08-09 17:02:31 +00:00
parent b1aedf30e0
commit 74a9ccb49d
7 changed files with 59 additions and 29 deletions

View File

@@ -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; }

View File

@@ -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
{

View File

@@ -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);
}

View File

@@ -57,17 +57,8 @@ FFmpegDecoderVideo::~FFmpegDecoderVideo()
{
OSG_INFO<<"Destructing FFmpegDecoderVideo..."<<std::endl;
this->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();
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;
}
}
};