gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog libmedia/ffmpeg/ffmpegNetStream...


From: Sandro Santilli
Subject: [Gnash-commit] gnash ChangeLog libmedia/ffmpeg/ffmpegNetStream...
Date: Mon, 12 May 2008 11:16:16 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Sandro Santilli <strk>  08/05/12 11:16:16

Modified files:
        .              : ChangeLog 
        libmedia/ffmpeg: ffmpegNetStreamUtil.h 
        server/asobj   : NetStreamFfmpeg.cpp NetStreamFfmpeg.h 

Log message:
                * libmedia/ffmpeg/ffmpegNetStreamUtil.h: drop multithread_queue,
                  substitute with ElementsOwningQueue.
                * server/asobj/NetStreamFfmpeg.{cpp,h}: use a simple
                  ElementsOwningQueue for audio/video queues, document more
                  the overlycomplex methods, sleep more in av_streamer when
                  queues are full.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.6589&r2=1.6590
http://cvs.savannah.gnu.org/viewcvs/gnash/libmedia/ffmpeg/ffmpegNetStreamUtil.h?cvsroot=gnash&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.cpp?cvsroot=gnash&r1=1.121&r2=1.122
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.h?cvsroot=gnash&r1=1.62&r2=1.63

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.6589
retrieving revision 1.6590
diff -u -b -r1.6589 -r1.6590
--- ChangeLog   12 May 2008 09:19:58 -0000      1.6589
+++ ChangeLog   12 May 2008 11:16:13 -0000      1.6590
@@ -1,5 +1,14 @@
 2008-05-12 Sandro Santilli <address@hidden>
 
+       * libmedia/ffmpeg/ffmpegNetStreamUtil.h: drop multithread_queue,
+         substitute with ElementsOwningQueue.
+       * server/asobj/NetStreamFfmpeg.{cpp,h}: use a simple
+         ElementsOwningQueue for audio/video queues, document more
+         the overlycomplex methods, sleep more in av_streamer when
+         queues are full.
+
+2008-05-12 Sandro Santilli <address@hidden>
+
        * server/asobj/NetStreamFfmpeg.{cpp,h}: complete use of cached
          sound_handler; add a mutex protecting generic access to the
          audio/video queues. The mutex will be locked by

Index: libmedia/ffmpeg/ffmpegNetStreamUtil.h
===================================================================
RCS file: /sources/gnash/gnash/libmedia/ffmpeg/ffmpegNetStreamUtil.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- libmedia/ffmpeg/ffmpegNetStreamUtil.h       28 Mar 2008 16:23:07 -0000      
1.5
+++ libmedia/ffmpeg/ffmpegNetStreamUtil.h       12 May 2008 11:16:14 -0000      
1.6
@@ -34,7 +34,7 @@
 }
 #endif
 
-#include <queue>
+#include <deque>
 
 #include <iconv.h>
 #include <SDL_audio.h>
@@ -62,78 +62,89 @@
 };
 
 
-/// Threadsafe elements-owning queue
+/// Elements-owning queue
 //
-/// This class is a threadsafe queue, using std:queue and locking.
-/// It is used to store decoded audio and video data which are waiting to be 
"played"
-/// Elements of the queue are owned by instances of this class.
+/// This class is a queue owning its elements and optionally
+/// limited in size.
 ///
 template<class T>
-class multithread_queue
+class ElementsOwningQueue
 {
 public:
 
-       multithread_queue() 
+       /// Construct a queue, limited by given amount of elements (20 by 
default)
+       ElementsOwningQueue(size_t limit=20) 
+               :
+               _limit(limit)
        {
        }
 
-       // Destroy all elements of the queue. Locks.
-       ~multithread_queue()
+       // Destroy all elements of the queue. 
+       ~ElementsOwningQueue()
        {
          clear();
        }
 
-       // Destroy all elements of the queue. Locks.
+       // Destroy all elements of the queue.
        void clear()
        {
-         boost::mutex::scoped_lock lock( _mutex );
-
-         while ( ! m_queue.empty() ) {
-           T x = m_queue.front();
-           m_queue.pop();
-           delete x;
+               for (typename container::iterator i=_queue.begin(),
+                               e=_queue.end();
+                       i!=e;
+                       ++i)
+               {
+                       delete *i;
          }
+               _queue.clear();
        }
 
-       /// Returns the size if the queue. Locks.
+       /// Returns the size if the queue. 
        //
        /// @return the size of the queue
        ///
        size_t size()
        {
-         boost::mutex::scoped_lock lock( _mutex );
+               return _queue.size();
+       }
 
-         size_t n = m_queue.size();
+       /// Return true if the queue is empty
+       bool empty()
+       {
+               return _queue.empty();
+       }
 
-         return n;
+       /// Return true if the queue is full
+       //
+       /// The function would never return true
+       /// if the queue has no limit..
+       ///
+       bool full()
+       {
+               if ( ! _limit ) return false;
+               return _queue.size() >= _limit;
+       }
+
+       /// Set queue limit
+       void setLimit(unsigned int limit)
+       {
+               _limit = limit;
        }
 
-       /// Pushes an element to the queue. Locks.
+       /// Pushes an element to the queue. 
        //
        /// @param member
        /// The element to be pushed unto the queue.
        ///
-       /// @return true if queue isn't full and the element was pushed to the 
queue,
-       /// or false if the queue was full, and the element wasn't push unto it.
+       /// @return false if the queue has reached its limit, true otherwise.
        ///
        bool push(T member)
        {
-         bool rc = false;
-         boost::mutex::scoped_lock lock( _mutex );
-
-         // We only keep max 20 items in the queue.
-         // If it's "full" the item must wait, see calls to 
-         // this function in read_frame() to see how it is 
-         // done.
-         if ( m_queue.size() < 20 ) {
-           m_queue.push( member );
-           rc = true;
-         }
-
-         return rc;
+               if ( _limit && _queue.size() >= _limit ) return false;
+               _queue.push_back( member );
+               return true;
        }
 
-       /// Returns a pointer to the first element on the queue. Locks.
+       /// Returns a pointer to the first element on the queue. 
        //
        /// If no elements are available this function returns NULL.
        ///
@@ -141,38 +152,32 @@
        ///
        T front()
        {
-         boost::mutex::scoped_lock lock( _mutex );
-       
-         T member = NULL;
-
-         if ( ! m_queue.empty() ) {
-           member = m_queue.front();
+               if ( _queue.empty() ) return 0;
+               return _queue.front();
          }
   
-         return member;
-       }
-
-       /// Pops the first element from the queue. Locks.
+       /// Pops the first element from the queue. 
        //
        /// If no elements are available this function is
        /// a noop. 
        ///
        void pop()
        {
-         boost::mutex::scoped_lock lock( _mutex );
-
-         if ( ! m_queue.empty() ) {
-           m_queue.pop();
-         }
+               if ( ! _queue.empty() ) _queue.pop_front();
        }
 
 private:
 
+       typedef std::deque<T> container;
+
+       /// Limit queue to this number of elements
+       unsigned int _limit;
+
        // Mutex used for locking
        boost::mutex _mutex;
 
        // The actual queue.
-       std::queue<T> m_queue;
+       container _queue;
 };
 
 

Index: server/asobj/NetStreamFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.cpp,v
retrieving revision 1.121
retrieving revision 1.122
diff -u -b -r1.121 -r1.122
--- server/asobj/NetStreamFfmpeg.cpp    12 May 2008 09:20:01 -0000      1.121
+++ server/asobj/NetStreamFfmpeg.cpp    12 May 2008 11:16:15 -0000      1.122
@@ -572,7 +572,13 @@
        m_Frame = avcodec_alloc_frame();
 
        {
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("image_mutex: waiting for lock in startPlayback");
+#endif
                boost::mutex::scoped_lock lock(image_mutex);
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("image_mutex: lock obtained in startPlayback");
+#endif
 
                // Determine required buffer size and allocate buffer
                if (m_videoFrameFormat == render::YUV)
@@ -584,6 +590,9 @@
                        m_imageframe = new image::rgb(m_VCodecCtx->width,       
m_VCodecCtx->height);
                }
 
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("image_mutex: releasing lock in startPlayback");
+#endif
        }
 
        if ( m_audio_index >= 0 && _soundHandler )
@@ -680,34 +689,54 @@
        // Loop while we're playing
        while (ns->m_go)
        {
+               unsigned long int sleepTime = 1000;
+
 #ifdef GNASH_DEBUG_THREADS
                log_debug("Decoding iteration. bufferTime=%lu, bufferLen=%lu", 
ns->bufferTime(), ns->bufferLength());
 #endif
 
                {
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: waiting for lock in av_streamer");
+#endif
                boost::mutex::scoped_lock lock(ns->_qMutex);
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: lock obtained in av_streamer");
+#endif
                if (ns->m_isFLV)
                {
-                       // If queues are full then don't bother filling it
-                       if ( ns->m_qvideo.size() < 20 || ns->m_qaudio.size() < 
20 ) 
-                       {
-
-                               // If we have problems with decoding - break
-                               if (!ns->decodeFLVFrame() && 
ns->m_start_onbuffer == false && ns->m_qvideo.size() == 0 && 
ns->m_qaudio.size() == 0)
-                               {
-                                       // TODO: do we really want to break 
here !?
-                                       break;
-                               }
-                       }
-                       else
+                       // If both queues are full then don't bother filling it
+                       if ( ns->m_qvideo.full() && ns->m_qaudio.full() )
                        {
                                // TODO: sleep till any of the two queues
                                //       falls under the given number
                                //       (20 currently, but should be a class 
member really)
                                //
                                // NOTE: audio_streamer pops from m_qaudio and
-                               //       refreshVideoFrame pops from m_qvideo
+                               //       refreshVideoFrame pops from m_qvideo, 
wouldn't know
+                               //       where to notify the condition from 
(both?)
                                //
+                               //log_debug("Queues full, sleeping more");
+                               sleepTime *= 4;
+                       }
+                       else
+                       {
+                               //log_debug("Calling decodeFLVFrame");
+                               bool successDecoding = ns->decodeFLVFrame();
+                               //log_debug("decodeFLVFrame returned %d", 
successDecoding);
+                               if ( ! successDecoding )
+                               {
+                                       // Possible failures:
+                                       // 1. could not decode frame... lot's 
of possible
+                                       //    reasons...
+                                       if ( ns->m_videoFrameFormat != 
render::NONE )
+                                       {
+                                               log_error("Could not decode FLV 
frame");
+                                               break;
+                                       }
+                                       // else it's expected, we'll keep going 
anyway
+                               }
+
                        }
 
                }
@@ -721,9 +750,14 @@
                        }
 
                }
+
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: releasing lock in av_streamer");
+#endif
                }
 
-               usleep(1000); // Sleep 1ms to avoid busying the processor.
+               //log_debug("Sleeping %d microseconds", sleepTime);
+               usleep(sleepTime); // Sleep 1ms to avoid busying the processor.
 
        }
 
@@ -752,7 +786,13 @@
 
        while (len > 0 && ns->m_qaudio.size() > 0)
        {
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: waiting for lock in audio_streamer");
+#endif
                boost::mutex::scoped_lock lock(ns->_qMutex);
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: lock obtained in audio_streamer");
+#endif
 
                media::raw_mediadata_t* samples = ns->m_qaudio.front();
 
@@ -771,6 +811,9 @@
                        delete samples;
                }
 
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: releasing lock in audio_streamer");
+#endif
        }
        return true;
 }
@@ -952,7 +995,6 @@
        avcodec_decode_video(m_VCodecCtx, m_Frame, &got, packet->data, 
packet->size);
        if (!got) return false;
 
-       boost::mutex::scoped_lock lock(image_mutex);
 
        if (m_imageframe == NULL)
        {
@@ -984,13 +1026,19 @@
        else if (m_videoFrameFormat == render::RGB && m_VCodecCtx->pix_fmt != 
PIX_FMT_RGB24)
        {
                rgbpicture = 
media::VideoDecoderFfmpeg::convertRGB24(m_VCodecCtx, *m_Frame);
-               if (!rgbpicture.data[0]) {
+               if (!rgbpicture.data[0])
+               {
+#ifdef GNASH_DEBUG_THREADS
+                       log_debug("image_mutex: releasing lock in decodeVideo");
+#endif
                        return false;
                }
        }
 
        media::raw_mediadata_t* video = new media::raw_mediadata_t();
 
+       image::image_base* tmpImage = NULL;
+
        if (m_videoFrameFormat == render::YUV)
        {
                video->m_data = new 
boost::uint8_t[static_cast<image::yuv*>(m_imageframe)->size()];
@@ -1089,6 +1137,10 @@
        if (m_isFLV) m_qvideo.push(video);
        else m_unqueued_data = m_qvideo.push(video) ? NULL : video;
 
+#ifdef GNASH_DEBUG_THREADS
+       log_debug("image_mutex: releasing lock in decodeVideo");
+#endif
+
        return true;
 }
 
@@ -1243,10 +1295,22 @@
 void
 NetStreamFfmpeg::refreshVideoFrame()
 {
+#ifdef GNASH_DEBUG_THREADS
+       log_debug("qMutex: waiting for lock in refreshVideoFrame");
+#endif
        boost::mutex::scoped_lock lock(_qMutex);
+#ifdef GNASH_DEBUG_THREADS
+       log_debug("qMutex: lock obtained in refreshVideoFrame");
+#endif
 
        // If we're paused or not running, there is no need to do this
-       if (!m_go || m_pause) return;
+       if (!m_go || m_pause)
+       {
+#ifdef GNASH_DEBUG_THREADS
+               log_debug("qMutex: releasing lock in refreshVideoFrame");
+#endif
+               return;
+       }
 
        // Loop until a good frame is found
        while(1)
@@ -1258,7 +1322,7 @@
                // If the queue is empty we have nothing to do
                if (!video)
                {
-                       return;
+                       break;
                }
 
                // Caclulate the current time
@@ -1279,7 +1343,17 @@
                // current time, we put it in the output image.
                if (current_clock >= video_clock)
                {
+
+#ifdef GNASH_DEBUG_THREADS
+                       log_debug("image_mutex: waiting for lock in 
refreshVideoFrame");
+#endif
+
                        boost::mutex::scoped_lock lock(image_mutex);
+
+#ifdef GNASH_DEBUG_THREADS
+                       log_debug("image_mutex: lock obtained in 
refreshVideoFrame");
+#endif
+
                        if (m_videoFrameFormat == render::YUV)
                        {
                                // XXX m_imageframe might be a byte aligned 
buffer, while video is not!
@@ -1299,15 +1373,22 @@
                        // A frame is ready for pickup
                        m_newFrameReady = true;
 
+#ifdef GNASH_DEBUG_THREADS
+                       log_debug("image_mutex: releasing lock in 
refreshVideoFrame");
+#endif
                }
                else
                {
                        // The timestamp on the first frame in the queue is 
greater
                        // than the current time, so no need to do anything.
-                       return;
+                       break;
                }
 
        }
+
+#ifdef GNASH_DEBUG_THREADS
+       log_debug("qMutex: releasing lock in refreshVideoFrame");
+#endif
 }
 
 

Index: server/asobj/NetStreamFfmpeg.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.h,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -b -r1.62 -r1.63
--- server/asobj/NetStreamFfmpeg.h      12 May 2008 09:20:01 -0000      1.62
+++ server/asobj/NetStreamFfmpeg.h      12 May 2008 11:16:16 -0000      1.63
@@ -138,24 +138,62 @@
        // Used to decode and push the next available (non-FLV) frame to the 
audio or video queue
        bool decodeMediaFrame();
 
-       /// Used to decode push the next available FLV frame to the audio or 
video queue
+       /// Used to push decoded version of next available FLV frame to the 
audio or video queue
        //
        /// Called by ::av_streamer to buffer more a/v frames when possible.
        ///
-       /// This is a non-blocking call, if data isn't available in the parser 
no
-       /// new frame is decoded and this method returns false. Note that this 
doesn't
-       /// necessarely means the FLV stream is ended, rather it is possible 
the loader
-       /// thread is starving. 
+       /// Will call decodeVideo or decodeAudio depending on frame type, and 
return
+       /// what they return.
+       /// Will set m_go to false on EOF from input.
        ///
-       /// TODO: return a more informative value to distinguish between EOF 
and starving
-       ///       conditions ?
+       /// This is a blocking call.
+       //
+       /// @returns :
+       ///     If next frame is video and:
+       ///             - we have no video decoding context
+       ///             - or there is a decoding error
+       ///             - or there is a conversion error
+       ///             - or renderer requested format is NONE
+       ///     ... false will be returned.
+       ///     If next frame is an audio frame and we have no audio decoding 
context, false is returned.
+       ///     In any other case, true is returned.
+       ///
+       /// NOTE: (FIXME) if we succeeded decoding but the relative queue was 
full,
+       ///       true will be returned but nothing would be pushed on the 
queues.
+       /// 
+       /// TODO: return a more informative value to tell what happened.
+       /// TODO: make it simpler !
        ///
        bool decodeFLVFrame();
 
-       // Used to decode a video frame and push it on the videoqueue
+       /// Used to decode a video frame and push it on the videoqueue
+       //
+       /// Also updates m_imageframe (why !??)
+       ///
+       /// This is a blocking call.
+       /// If no Video decoding context exists (m_VCodecCtx), false is 
returned.
+       /// On decoding (or converting) error, false is returned.
+       /// If renderer requested video format is render::NONE, false is 
returned.
+       /// In any other case, true is returned.
+       ///
+       /// NOTE: (FIXME) if video queue is full, 
+       ///       we'd still return true w/out pushing anything new there
+       /// 
+       /// TODO: return a more informative value to tell what happened.
+       ///
        bool decodeVideo( AVPacket* packet );
 
-       // Used to decode a audio frame and push it on the audioqueue
+       /// Used to decode a audio frame and push it on the audioqueue
+       //
+       /// This is a blocking call.
+       /// If no Video decoding context exists (m_ACodecCtx), false is 
returned.
+       /// In any other case, true is returned.
+       ///
+       /// NOTE: (FIXME) if audio queue is full,
+       ///       we'd still return true w/out pushing anything new there
+       /// 
+       /// TODO: return a more informative value to tell what happened.
+       ///
        bool decodeAudio( AVPacket* packet );
 
        // Used to calculate a decimal value from a ffmpeg fraction
@@ -197,8 +235,10 @@
        boost::uint32_t m_current_timestamp;
 
        /// The queues of audio and video data.
-       media::multithread_queue <media::raw_mediadata_t*> m_qaudio;
-       media::multithread_queue <media::raw_mediadata_t*> m_qvideo;
+       typedef media::ElementsOwningQueue<media::raw_mediadata_t*> MediaQueue;
+
+       MediaQueue m_qaudio;
+       MediaQueue m_qvideo;
 
        /// Mutex protecting access to queues
        boost::mutex _qMutex;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]