[Top][All Lists]
[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;
- [Gnash-commit] gnash ChangeLog libmedia/ffmpeg/ffmpegNetStream...,
Sandro Santilli <=