[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog libbase/FLVParser.cpp libbase/L...
From: |
Tomas Groth |
Subject: |
[Gnash-commit] gnash ChangeLog libbase/FLVParser.cpp libbase/L... |
Date: |
Fri, 30 Mar 2007 13:57:28 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Tomas Groth <tgc> 07/03/30 13:57:27
Modified files:
. : ChangeLog
libbase : FLVParser.cpp LoadThread.cpp LoadThread.h
server/asobj : NetConnection.cpp NetConnection.h NetStream.cpp
NetStream.h NetStreamFfmpeg.cpp
NetStreamFfmpeg.h NetStreamGst.cpp
NetStreamGst.h
testsuite/actionscript.all: NetStream.as
Log message:
* libbase/FLVParser.cpp: Fixed a few bugs.
* libbase/LoadThread.{h,cpp}: Changed to use a cache so we avoid
blocking to often when reading and loading at the same time.
* server/asobj/NetConnection.{h,cpp}: Added loadCompleted().
* server/asobj/NetStream.{h,cpp}: Added setEnvironment(), and
removed the getter/setter for onStatus.
* server/asobj/NetStreamFfmpeg.{h,cpp}: Fixed a big mem-leak.
Added
setEnvironment(), and added support for status/error messages.
* server/asobj/NetStreamGst.{h,cpp}: Added setEnvironment(), and
added support for status/error messages.
* testsuite/actionscript.all/NetStream.as: Corrected expected
results for onStatus, and added some for onCuePoint and
onMetaData.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.2732&r2=1.2733
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/FLVParser.cpp?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/LoadThread.cpp?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/LoadThread.h?cvsroot=gnash&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetConnection.cpp?cvsroot=gnash&r1=1.34&r2=1.35
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetConnection.h?cvsroot=gnash&r1=1.22&r2=1.23
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStream.cpp?cvsroot=gnash&r1=1.33&r2=1.34
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStream.h?cvsroot=gnash&r1=1.24&r2=1.25
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.cpp?cvsroot=gnash&r1=1.25&r2=1.26
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamFfmpeg.h?cvsroot=gnash&r1=1.15&r2=1.16
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamGst.cpp?cvsroot=gnash&r1=1.17&r2=1.18
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/NetStreamGst.h?cvsroot=gnash&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/NetStream.as?cvsroot=gnash&r1=1.9&r2=1.10
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.2732
retrieving revision 1.2733
diff -u -b -r1.2732 -r1.2733
--- ChangeLog 30 Mar 2007 13:41:10 -0000 1.2732
+++ ChangeLog 30 Mar 2007 13:57:26 -0000 1.2733
@@ -1,3 +1,18 @@
+2007-03-30 Tomas Groth Christensen <address@hidden>
+
+ * libbase/FLVParser.cpp: Fixed a few bugs.
+ * libbase/LoadThread.{h,cpp}: Changed to use a cache so we avoid
+ blocking to often when reading and loading at the same time.
+ * server/asobj/NetConnection.{h,cpp}: Added loadCompleted().
+ * server/asobj/NetStream.{h,cpp}: Added setEnvironment(), and
+ removed the getter/setter for onStatus.
+ * server/asobj/NetStreamFfmpeg.{h,cpp}: Fixed a big mem-leak. Added
+ setEnvironment(), and added support for status/error messages.
+ * server/asobj/NetStreamGst.{h,cpp}: Added setEnvironment(), and
+ added support for status/error messages.
+ * testsuite/actionscript.all/NetStream.as: Corrected expected
+ results for onStatus, and added some for onCuePoint and onMetaData.
+
2007-03-30 Sandro Santilli <address@hidden>
* server/dlist.cpp (clear_except): don't copy display list (small
Index: libbase/FLVParser.cpp
===================================================================
RCS file: /sources/gnash/gnash/libbase/FLVParser.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libbase/FLVParser.cpp 28 Mar 2007 16:12:08 -0000 1.2
+++ libbase/FLVParser.cpp 30 Mar 2007 13:57:26 -0000 1.3
@@ -16,7 +16,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: FLVParser.cpp,v 1.2 2007/03/28 16:12:08 tgc Exp $
+// $Id: FLVParser.cpp,v 1.3 2007/03/30 13:57:26 tgc Exp $
#include "FLVParser.h"
#include "amf.h"
@@ -84,10 +84,12 @@
uint32_t video_size = _videoFrames.size();
uint32_t audio_size = _audioFrames.size();
+ if (!(audio_size <= static_cast<uint32_t>(_lastAudioFrame+1) &&
video_size <= static_cast<uint32_t>(_lastVideoFrame+1))) {
// Parse a media frame if any left or if needed
while(video_size == _videoFrames.size() && audio_size ==
_audioFrames.size() && !_parsingComplete) {
- parseNextFrame();
+ if (!parseNextFrame()) break;
+ }
}
// Find the next frame in the file
@@ -145,7 +147,7 @@
// Make sure that there are parsed enough frames to return the need
frame
while(_audioFrames.size() <= static_cast<uint32_t>(_lastAudioFrame+1)
&& !_parsingComplete) {
- parseNextFrame();
+ if (!parseNextFrame()) break;
}
// If the needed frame can't be parsed (EOF reached) return NULL
@@ -173,7 +175,7 @@
// Make sure that there are parsed enough frames to return the need
frame
while(_videoFrames.size() <= static_cast<uint32_t>(_lastVideoFrame+1)
&& !_parsingComplete) {
- parseNextFrame();
+ if (!parseNextFrame()) break;
}
// If the needed frame can't be parsed (EOF reached) return NULL
@@ -342,6 +344,7 @@
FLVAudioInfo* FLVParser::getAudioInfo()
{
+
boost::mutex::scoped_lock lock(_mutex);
// If there are no audio in this FLV return NULL
@@ -362,12 +365,11 @@
bool FLVParser::isTimeLoaded(uint32_t time)
{
-
boost::mutex::scoped_lock lock(_mutex);
// Parse frames until the need time is found, or EOF
- while (!_parsingComplete && (_videoFrames.size() > 0 &&
_videoFrames.back()->timestamp < time) && (_audioFrames.size() > 0 &&
_audioFrames.back()->timestamp < time)) {
- parseNextFrame();
+ while (!_parsingComplete && _videoFrames.size() > 0 &&
_videoFrames.back()->timestamp < time && _audioFrames.size() > 0 &&
_audioFrames.back()->timestamp < time) {
+ if (!parseNextFrame()) break;
}
if (_videoFrames.size() > 0 && _videoFrames.back()->timestamp >= time) {
@@ -377,6 +379,7 @@
if (_audioFrames.size() > 0 && _audioFrames.back()->timestamp >= time) {
return true;
}
+
return false;
}
@@ -510,7 +513,9 @@
_lastParsedPosition += 15 + bodyLength;
} else {
_parsingComplete = true;
+ return false;
}
+
return true;
}
Index: libbase/LoadThread.cpp
===================================================================
RCS file: /sources/gnash/gnash/libbase/LoadThread.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libbase/LoadThread.cpp 24 Mar 2007 14:36:47 -0000 1.3
+++ libbase/LoadThread.cpp 30 Mar 2007 13:57:26 -0000 1.4
@@ -16,17 +16,22 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: LoadThread.cpp,v 1.3 2007/03/24 14:36:47 tgc Exp $
+// $Id: LoadThread.cpp,v 1.4 2007/03/30 13:57:26 tgc Exp $
#include "LoadThread.h"
LoadThread::LoadThread()
:
- _bytesLoaded(0),
_completed(false),
_loadPosition(0),
_userPosition(0),
- _actualPosition(0)
+ _actualPosition(0),
+ _cache(NULL),
+ _cacheStart(0),
+ _cachedData(0),
+ _cacheSize(0),
+ _chunkSize(56),
+ _streamSize(0)
{
}
@@ -34,6 +39,7 @@
{
// stop the download thread if it's still runnning
completed();
+ if (_cache) delete[] _cache;
}
bool LoadThread::setStream(std::auto_ptr<tu_file> stream)
@@ -41,6 +47,7 @@
_stream = stream;
if (_stream.get() != NULL) {
// Start the downloading.
+ setupCache();
_thread.reset( new
boost::thread(boost::bind(LoadThread::downloadThread, this)) );
return true;
@@ -55,18 +62,27 @@
// true is the new position is equal the wanted,
// or else return false
- boost::mutex::scoped_lock lock(_mutex);
- _stream->set_position(pos);
- unsigned int ret = _stream->get_position();
- _userPosition = ret;
- _actualPosition = _userPosition;
- return (pos == ret);
+ if (_loadPosition >= static_cast<long>(pos)) {
+ _userPosition = pos;
+ return true;
+ } else {
+ _userPosition = _loadPosition;
+ return false;
+ }
}
size_t LoadThread::read(void *dst, size_t bytes)
{
- boost::mutex::scoped_lock lock(_mutex);
+ // If the data is in the cache we used it
+ if (_cacheStart <= _userPosition && static_cast<long>(bytes) +
_userPosition <= _cacheStart + _cachedData) {
+ memcpy(dst, _cache + (_userPosition - _cacheStart), bytes);
+ _userPosition += bytes;
+ return bytes;
+
+ // If the data is not in cache, but the file is completely loaded
+ // we just get the data directly from the stream
+ } else if (_completed) {
// If the actual position is different from the position
// last used by the user/owner, seek to the position
@@ -81,12 +97,17 @@
_userPosition += ret;
_actualPosition = _userPosition;
return ret;
-}
+ }
+
+ // The wanted data wasen't in the cache, and the file isn't loaded
+ // so we now either load more data into the cache, or completely
+ // replace the content.
-bool LoadThread::eof()
-{
boost::mutex::scoped_lock lock(_mutex);
+ // If the new data can fit in the cache we just load it into it
+ if (_cacheStart <= _userPosition && static_cast<long>(bytes) +
_userPosition < _cacheStart + _cacheSize) {
+
// If the actual position is different from the position
// last used by the user/owner, seek to the position
if (_actualPosition != _userPosition) {
@@ -94,30 +115,88 @@
_actualPosition = _userPosition;
}
- // Check if we're at the EOF
- return _stream->get_eof();
+ // Try to read a wanted amount of bytes into the given
+ // buffer, note the new position and return the actual amount
read
+ int ret = _stream->read_bytes(dst, bytes);
+
+ memcpy(_cache +(_userPosition - _cacheStart), dst, ret);
+ _cachedData = _userPosition - _cacheStart + ret;
+ _userPosition += ret;
+ _actualPosition = _userPosition;
+ return ret;
+
+ }
+
+ // We need to replace the cache...
+
+ // check if the cache is big enough to contain the wanted data
+ if (static_cast<long>(bytes) > _cacheSize-20000) {
+ delete[] _cache;
+ _cacheSize = bytes+20000;
+ _cache = new uint8_t[_cacheSize];
+ }
+
+ // To avoid recaching all the time, we cache some data from before
+ // the _userPosition
+ long newcachestart = _userPosition;
+ if (_userPosition > 20000) {
+ newcachestart = _userPosition - 20000;
+ }
+
+ // Amount to read into the cache
+ long readdata = 0;
+ if (_loadPosition >= newcachestart + _cacheSize) readdata = _cacheSize;
+ else if (_loadPosition < newcachestart + _cacheSize && _loadPosition >
_userPosition + static_cast<long>(bytes)) readdata = _loadPosition -
newcachestart;
+ else readdata = bytes + (_userPosition - newcachestart);
+
+ // If the actual position is different from the position
+ // last used by the user/owner, seek to the position
+ if (_actualPosition != _userPosition) {
+ _stream->set_position(newcachestart);
+ _actualPosition = newcachestart;
+ }
+
+
+ // Try to read a wanted amount of bytes into the given
+ // buffer, note the new position and return the actual amount read
+ int ret = _stream->read_bytes(_cache, readdata);
+ _cachedData = ret;
+ _cacheStart = newcachestart;
+
+ if (ret < _userPosition - newcachestart) return 0;
+
+ int newret = bytes;
+ if (static_cast<int>(bytes) > ret) newret = ret - (_userPosition -
newcachestart);
+
+ memcpy(dst, _cache + (_userPosition - newcachestart), newret);
+ _userPosition += newret;
+ _actualPosition = newcachestart + _cachedData;
+ if (newcachestart + _cachedData > _loadPosition) _loadPosition =
_actualPosition;
+ return newret;
}
-size_t LoadThread::tell()
+bool LoadThread::eof()
{
+ // Check if we're at the EOF
+ if (_completed && _userPosition >= _loadPosition) return true;
+ else return false;
+}
- boost::mutex::scoped_lock lock(_mutex);
+size_t LoadThread::tell()
+{
return _userPosition;
}
long LoadThread::getBytesLoaded()
{
- boost::mutex::scoped_lock lock(_mutex);
-
// The load position is equal to the bytesloaded
return _loadPosition;
}
long LoadThread::getBytesTotal()
{
- boost::mutex::scoped_lock lock(_mutex);
- return _stream->get_size();
+ return _streamSize;
}
bool LoadThread::completed()
@@ -131,24 +210,64 @@
return _completed;
}
-void LoadThread::downloadThread(LoadThread* lt)
+void LoadThread::setupCache()
{
+ boost::mutex::scoped_lock lock(_mutex);
+ _cache = new uint8_t[1024*500];
+ _cacheSize = 1024*500;
+
+ int ret = _stream->read_bytes(_cache, 1024);
+ _cacheStart = 0;
+ _cachedData = ret;
+ _loadPosition = 1024;
+ _streamSize = _stream->get_size();
+}
+
+void LoadThread::downloadThread(LoadThread* lt)
+{
// Until the download is completed keep downloading
while (!lt->_completed) {
- lt->download();
+ if (lt->_chunkSize + lt->_loadPosition > lt->_cacheStart +
lt->_cacheSize) lt->download();
+ else lt->fillCache();
}
}
+void LoadThread::fillCache()
+{
+ if (_loadPosition >= _streamSize) {
+ _completed = true;
+ return;
+ }
+
+ boost::mutex::scoped_lock lock(_mutex);
+
+ if (_loadPosition != _actualPosition)
_stream->set_position(_loadPosition);
+
+ int ret = _stream->read_bytes(_cache+_cachedData, _chunkSize);
+
+ if (ret != _chunkSize) {
+ _completed = true;
+ }
+ _cachedData += ret;
+ _loadPosition = _loadPosition + ret;
+ _actualPosition = _loadPosition;
+}
+
void LoadThread::download()
{
+ if (_loadPosition >= _streamSize) {
+ _completed = true;
+ return;
+ }
+
boost::mutex::scoped_lock lock(_mutex);
- size_t CHUNK_SIZE = 1024;
- _stream->set_position(_loadPosition + CHUNK_SIZE);
+
+ _stream->set_position(_loadPosition + _chunkSize);
unsigned int pos = _stream->get_position();
- if (pos != _loadPosition + CHUNK_SIZE) {
+ if (pos != _loadPosition + _chunkSize) {
_completed = true;
}
_loadPosition = pos;
@@ -157,6 +276,5 @@
bool LoadThread::isPositionConfirmed(size_t pos)
{
- boost::mutex::scoped_lock lock(_mutex);
return (static_cast<int32_t>(pos) <= _loadPosition);
}
Index: libbase/LoadThread.h
===================================================================
RCS file: /sources/gnash/gnash/libbase/LoadThread.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libbase/LoadThread.h 24 Mar 2007 14:36:47 -0000 1.4
+++ libbase/LoadThread.h 30 Mar 2007 13:57:26 -0000 1.5
@@ -19,7 +19,7 @@
#ifndef __LOADTHREAD_H__
#define __LOADTHREAD_H__
-// $Id: LoadThread.h,v 1.4 2007/03/24 14:36:47 tgc Exp $
+// $Id: LoadThread.h,v 1.5 2007/03/30 13:57:26 tgc Exp $
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
@@ -98,20 +98,42 @@
/// The function that does the actual downloading
void download();
+ /// Fills the cache at the begining
+ void setupCache();
+
+ /// Fills the cache when needed
+ void fillCache();
+
/// The stream/file we want to access
std::auto_ptr<tu_file> _stream;
- long _bytesLoaded;
-
- bool _completed;
+ volatile bool _completed;
boost::mutex _mutex;
std::auto_ptr<boost::thread> _thread;
- long _loadPosition;
- long _userPosition;
- long _actualPosition;
+ volatile long _loadPosition;
+ volatile long _userPosition;
+ volatile long _actualPosition;
+
+ // Cache...
+ uint8_t* _cache;
+
+ // The fileposition where the cache start
+ volatile long _cacheStart;
+
+ // Data amount in the cache
+ volatile long _cachedData;
+
+ // Size of the cache
+ volatile long _cacheSize;
+
+ // The amount we load at one go
+ long _chunkSize;
+
+ // size of the stream
+ long _streamSize;
};
#endif // __LOADTHREAD_H__
Index: server/asobj/NetConnection.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetConnection.cpp,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -b -r1.34 -r1.35
--- server/asobj/NetConnection.cpp 28 Mar 2007 16:12:08 -0000 1.34
+++ server/asobj/NetConnection.cpp 30 Mar 2007 13:57:27 -0000 1.35
@@ -14,7 +14,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: NetConnection.cpp,v 1.34 2007/03/28 16:12:08 tgc Exp $ */
+/* $Id: NetConnection.cpp,v 1.35 2007/03/30 13:57:27 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -173,6 +173,14 @@
return _loader->getBytesLoaded();
}
+/*public*/
+bool
+NetConnection::loadCompleted()
+{
+ if (!_loader) return false;
+ return _loader->completed();
+}
+
bool
NetConnection::connectParser(FLVParser* parser)
{
Index: server/asobj/NetConnection.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetConnection.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -b -r1.22 -r1.23
--- server/asobj/NetConnection.h 23 Mar 2007 00:30:10 -0000 1.22
+++ server/asobj/NetConnection.h 30 Mar 2007 13:57:27 -0000 1.23
@@ -14,7 +14,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: NetConnection.h,v 1.22 2007/03/23 00:30:10 tgc Exp $ */
+/* $Id: NetConnection.h,v 1.23 2007/03/30 13:57:27 tgc Exp $ */
#ifndef __NETCONNECTION_H__
#define __NETCONNECTION_H__
@@ -83,6 +83,8 @@
/// Connects FLV parser with the LoadThread
bool connectParser(FLVParser* parser);
+ /// Returns whether the load is complete
+ bool loadCompleted();
private:
/// the url of the file
Index: server/asobj/NetStream.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStream.cpp,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -b -r1.33 -r1.34
--- server/asobj/NetStream.cpp 23 Mar 2007 00:30:10 -0000 1.33
+++ server/asobj/NetStream.cpp 30 Mar 2007 13:57:27 -0000 1.34
@@ -15,7 +15,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-/* $Id: NetStream.cpp,v 1.33 2007/03/23 00:30:10 tgc Exp $ */
+/* $Id: NetStream.cpp,v 1.34 2007/03/30 13:57:27 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -75,6 +75,7 @@
if ( ns )
{
netstream_obj->setNetCon(ns);
+ netstream_obj->setEnvironment(&fn.env());
}
else
{
@@ -215,27 +216,6 @@
return as_value();
}
-// Both a getter and a setter for onStatus
-static as_value
-netstream_onstatus(const fn_call& fn)
-{
-
- boost::intrusive_ptr<NetStream> ns = ensureType<NetStream>(fn.this_ptr);
-
- if ( fn.nargs == 0 ) // getter
- {
- as_function* h = ns->getStatusHandler();
- if ( h ) return as_value(h);
- else return as_value();
- }
- else // setter
- {
- as_function* h = fn.arg(0).to_as_function();
- if ( h ) ns->setStatusHandler(h);
- }
- return as_value();
-}
-
void
attachNetStreamInterface(as_object& o)
{
@@ -260,8 +240,6 @@
gettersetter = new builtin_function(&netstream_bytestotal, NULL);
o.init_property("bytesTotal", *gettersetter, *gettersetter);
- gettersetter = new builtin_function(&netstream_onstatus, NULL);
- o.init_property("onStatus", *gettersetter, *gettersetter);
}
static as_object*
Index: server/asobj/NetStream.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStream.h,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -b -r1.24 -r1.25
--- server/asobj/NetStream.h 23 Mar 2007 00:30:10 -0000 1.24
+++ server/asobj/NetStream.h 30 Mar 2007 13:57:27 -0000 1.25
@@ -18,7 +18,7 @@
//
//
-/* $Id: NetStream.h,v 1.24 2007/03/23 00:30:10 tgc Exp $ */
+/* $Id: NetStream.h,v 1.25 2007/03/30 13:57:27 tgc Exp $ */
#ifndef __NETSTREAM_H__
#define __NETSTREAM_H__
@@ -92,6 +92,8 @@
virtual as_function* getStatusHandler() { return NULL; }
virtual void setStatusHandler(as_function*) { }
+
+ virtual void setEnvironment(as_environment* /*env*/) { };
};
Index: server/asobj/NetStreamFfmpeg.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.cpp,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -b -r1.25 -r1.26
--- server/asobj/NetStreamFfmpeg.cpp 28 Mar 2007 16:12:08 -0000 1.25
+++ server/asobj/NetStreamFfmpeg.cpp 30 Mar 2007 13:57:27 -0000 1.26
@@ -14,7 +14,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: NetStreamFfmpeg.cpp,v 1.25 2007/03/28 16:12:08 tgc Exp $ */
+/* $Id: NetStreamFfmpeg.cpp,v 1.26 2007/03/30 13:57:27 tgc Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -30,6 +30,7 @@
#include "movie_root.h"
#include "NetConnection.h"
#include "sound_handler.h"
+#include "action.h"
#if defined(_WIN32) || defined(WIN32)
#include <Windows.h> // for sleep()
@@ -70,7 +71,9 @@
m_isFLV(false),
m_newFrameReady(false),
m_bufferTime(100),
- m_statusChanged(false)
+ m_statusChanged(false),
+ m_start_onbuffer(false),
+ m_env(NULL)
{
}
@@ -80,10 +83,16 @@
if (m_parser) delete m_parser;
}
+void NetStreamFfmpeg::setEnvironment(as_environment* env)
+{
+ m_env = env;
+}
+
+
// called from avstreamer thread, and a few other places... (thread safe?)
void NetStreamFfmpeg::set_status(const char* status)
{
- m_status = status;
+ m_status_messages.push_back(status);
m_statusChanged = true;
}
@@ -272,12 +281,14 @@
// Check if the file is a FLV, in which case we use our own parser
uint8_t head[3];
- nc->read(head, 3);
+ if (nc->read(head, 3) < 3) {
+ ns->set_status("NetStream.Buffer.StreamNotFound");
+ return;
+ }
nc->seek(0);
if (head[0] == 'F' && head[1] == 'L' && head[2] == 'V') {
ns->m_isFLV = true;
-
ns->m_parser = new FLVParser();
if (!nc->connectParser(ns->m_parser)) {
ns->set_status("NetStream.Buffer.StreamNotFound");
@@ -315,6 +326,7 @@
ns->m_VCodecCtx = avcodec_alloc_context();
avcodec_open(ns->m_VCodecCtx, vcodec);
}
+ delete videoInfo;
// Get audio info from the parser
FLVAudioInfo* audioInfo = ns->m_parser->getAudioInfo();
@@ -335,6 +347,7 @@
ns->m_ACodecCtx = avcodec_alloc_context();
avcodec_open(ns->m_ACodecCtx, acodec);
}
+ delete audioInfo;
// We just define the indexes here, they're not really used when
// the file format is FLV
@@ -345,6 +358,7 @@
if (s) s->attach_aux_streamer(audio_streamer, (void*) ns);
// ns->m_pause = false;
+ ns->m_start_onbuffer = true;
// Allocate a frame to store the decoded frame in
ns->m_Frame = avcodec_alloc_frame();
@@ -534,7 +548,7 @@
continue;
}
- if (ns->read_frame() == false)
+ if (ns->read_frame() == false && ns->m_start_onbuffer == false)
{
if (ns->m_qvideo.size() == 0)
{
@@ -563,7 +577,7 @@
}
else
{
- delay = int((video_clock - clock)*1000000);
+ delay = int((video_clock - clock)*100000000);
}
// Don't hog the CPU.
@@ -641,8 +655,18 @@
int rc;
if (m_isFLV) {
FLVFrame* frame = m_parser->nextMediaFrame();
+
if (frame == NULL) {
+ if (_netCon->loadCompleted()) {
+ // Stop!
+ m_go = false;
+ } else {
+ // We pause and load and buffer a second before
continuing.
+ m_pause = true;
+ m_bufferTime =
static_cast<uint32_t>(m_video_clock) * 1000 + 1000;
set_status("NetStream.Buffer.Empty");
+ m_start_onbuffer = true;
+ }
return false;
}
@@ -826,7 +850,7 @@
boost::mutex::scoped_lock lock(decoding_mutex);
long newpos = 0;
- double timebase;
+ double timebase = 0;
// Seek to new position
if (m_isFLV) {
@@ -900,20 +924,37 @@
void
NetStreamFfmpeg::advance()
{
- if (m_go && m_pause && !m_imageframe && m_parser &&
m_parser->isTimeLoaded(m_bufferTime)) {
+ // Check if we should start the playback when a certain amount is
buffered
+ if (m_go && m_pause && m_start_onbuffer && m_parser &&
m_parser->isTimeLoaded(m_bufferTime)) {
set_status("NetStream.Buffer.Full");
m_pause = false;
+ m_start_onbuffer = false;
}
- if (m_statusChanged) {
-/* fn_call dummy(NULL, NULL, 0, 0);
- as_value info_asv(infoobject_new(dummy));
- boost::intrusive_ptr<as_object> info = info_asv.to_object();
+ // Check if there are any new status messages, and if we should
+ // pass them to a event handler
+ as_value status;
+ if (m_statusChanged && get_member(std::string("onStatus"), &status) &&
status.to_as_function() != NULL) {
- fn_call fn(this, v, 0, 0);
+ for (int i = m_status_messages.size()-1; i >= 0; --i) {
+ boost::intrusive_ptr<as_object> o = new as_object();
+ o->init_member(std::string("code"),
as_value(m_status_messages[i]), 1);
- m_statusHandler.get()->call(fn);*/
+ if (m_status_messages[i].find("StreamNotFound") ==
string::npos && m_status_messages[i].find("InvalidTime") == string::npos) {
+ o->init_member(std::string("level"),
as_value("status"), as_prop_flags::dontDelete|as_prop_flags::dontEnum);
+ } else {
+ o->init_member(std::string("level"),
as_value("error"), as_prop_flags::dontDelete|as_prop_flags::dontEnum);
+ }
+ m_env->push(o.get());
+ call_method0(status, m_env, this);
+
+ }
+ m_status_messages.clear();
+ m_statusChanged = false;
+ } else if (m_statusChanged) {
+ m_status_messages.clear();
+ m_statusChanged = false;
}
}
Index: server/asobj/NetStreamFfmpeg.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamFfmpeg.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -b -r1.15 -r1.16
--- server/asobj/NetStreamFfmpeg.h 23 Mar 2007 00:30:10 -0000 1.15
+++ server/asobj/NetStreamFfmpeg.h 30 Mar 2007 13:57:27 -0000 1.16
@@ -14,7 +14,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: NetStreamFfmpeg.h,v 1.15 2007/03/23 00:30:10 tgc Exp $ */
+/* $Id: NetStreamFfmpeg.h,v 1.16 2007/03/30 13:57:27 tgc Exp $ */
#ifndef __NETSTREAMFFMPEG_H__
#define __NETSTREAMFFMPEG_H__
@@ -60,7 +60,7 @@
~raw_videodata_t()
{
- if (m_size > 0) delete [] m_data;
+ if (m_data) delete [] m_data;
};
int m_stream_index;
@@ -156,7 +156,7 @@
bool newFrameReady();
as_function* getStatusHandler();
void setStatusHandler(as_function*);
-
+ void setEnvironment(as_environment* env);
// Used for ffmpeg data read and seek callbacks
static int readPacket(void* opaque, uint8_t* buf, int buf_size);
static offset_t seekMedia(void *opaque, offset_t offset, int whence);
@@ -229,7 +229,7 @@
multithread_queue <raw_videodata_t*> m_qvideo;
// paused or not
- bool m_pause;
+ volatile bool m_pause;
// The time ws started playing
double m_start_clock;
@@ -254,15 +254,20 @@
// The size of the buffer in milliseconds
uint32_t m_bufferTime;
- // The status message
- std::string m_status;
-
// Has the status message been updated?
volatile bool m_statusChanged;
// The handler which is invoked on status change
boost::intrusive_ptr<as_function> m_statusHandler;
+ // should we start when buffer is full?
+ bool m_start_onbuffer;
+
+ // The actionscript enviroment for the AS callbacks
+ as_environment* m_env;
+
+ // List of status messages to be processed
+ std::vector<std::string> m_status_messages;
};
} // gnash namespace
Index: server/asobj/NetStreamGst.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamGst.cpp,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- server/asobj/NetStreamGst.cpp 28 Mar 2007 22:21:29 -0000 1.17
+++ server/asobj/NetStreamGst.cpp 30 Mar 2007 13:57:27 -0000 1.18
@@ -30,6 +30,7 @@
#include "render.h"
#include "movie_root.h"
#include "NetConnection.h"
+#include "action.h"
#include "gstgnashsrc.h"
@@ -86,7 +87,10 @@
videowidth(0),
videoheight(0),
m_newFrameReady(false),
- m_parser(NULL)
+ m_parser(NULL),
+ m_env(NULL),
+ m_pausePlayback(false),
+ m_start_onbuffer(false)
{
}
@@ -95,10 +99,18 @@
close();
}
-// called from avstreamer thread
-void NetStreamGst::set_status(const char* /*code*/)
+void NetStreamGst::set_status(const char* status)
{
+ std::string std_status = status;
+ if (!(m_status_messages.size() > 0 &&
m_status_messages.back().compare(std_status) == 0)) {
+ m_status_messages.push_back(std_status);
+ m_statusChanged = true;
+ }
+}
+void NetStreamGst::setEnvironment(as_environment* env)
+{
+ m_env = env;
}
void NetStreamGst::pause(int mode)
@@ -111,8 +123,10 @@
{
m_pause = (mode == 0) ? true : false;
}
+ if (pipeline) {
if (m_pause) gst_element_set_state (GST_ELEMENT (pipeline),
GST_STATE_PAUSED);
else gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
+ }
}
void NetStreamGst::close()
@@ -170,6 +184,7 @@
// Callback function used by Gstreamer to to attached audio and video streams
// detected by decoderbin to either the video out or audio out elements.
+// Only used when not playing FLV
void
NetStreamGst::callback_newpad (GstElement* /*decodebin*/, GstPad *pad,
gboolean /*last*/, gpointer data)
{
@@ -271,12 +286,17 @@
// The callback function which refills the audio buffer with data
+// Only used when playing FLV
void NetStreamGst::audio_callback_handoff (GstElement * /*c*/, GstBuffer
*buffer, GstPad* /*pad*/, gpointer user_data)
{
NetStreamGst* ns = static_cast<NetStreamGst*>(user_data);
FLVFrame* frame = ns->m_parser->nextAudioFrame();
- if (!frame) return;
+ if (!frame) {
+ ns->set_status("NetStream.Buffer.Empty");
+ ns->m_pausePlayback = true;
+ return;
+ }
// if (GST_BUFFER_DATA(buffer)) delete [] GST_BUFFER_DATA(buffer);
GST_BUFFER_SIZE(buffer) = frame->dataSize;
@@ -287,12 +307,18 @@
}
+// The callback function which refills the video buffer with data
+// Only used when playing FLV
void NetStreamGst::video_callback_handoff (GstElement * /*c*/, GstBuffer
*buffer, GstPad* /*pad*/, gpointer user_data)
{
NetStreamGst* ns = static_cast<NetStreamGst*>(user_data);
FLVFrame* frame = ns->m_parser->nextVideoFrame();
- if (!frame) return;
+ if (!frame) {
+ ns->set_status("NetStream.Buffer.Empty");
+ ns->m_pausePlayback = true;
+ return;
+ }
// if (GST_BUFFER_DATA(buffer)) delete [] GST_BUFFER_DATA(buffer);
GST_BUFFER_SIZE(buffer) = frame->dataSize;
@@ -301,6 +327,7 @@
delete frame;
return;
}
+
void
NetStreamGst::startPlayback(NetStreamGst* ns)
{
@@ -318,7 +345,10 @@
ns->inputPos = 0;
uint8_t head[3];
- if (nc->read(head,3) < 3) return;
+ if (nc->read(head, 3) < 3) {
+ ns->set_status("NetStream.Buffer.StreamNotFound");
+ return;
+ }
nc->seek(0);
if (head[0] == 'F'|| head[1] == 'L' || head[2] == 'V') {
ns->m_isFLV = true;
@@ -417,6 +447,13 @@
"flvversion", G_TYPE_INT, 1,
NULL);
ns->videodecoder = gst_element_factory_make
("ffdec_flv", NULL);
+
+ // Check if the element was correctly created
+ if (!ns->videodecoder) {
+ log_error("A gstreamer flashvideo (h.263)
decoder element could not be created! You probably need to install
gst-ffmpeg.");
+ return;
+ }
+
} else if (videoInfo->codec == VIDEO_CODEC_VP6) {
videonincaps = gst_caps_new_simple ("video/x-vp6-flash",
"width", G_TYPE_INT, 320, // We don't yet have
a size extract for this codec, so we guess...
@@ -424,6 +461,13 @@
"framerate", GST_TYPE_FRACTION, fps, 1,
NULL);
ns->videodecoder = gst_element_factory_make
("ffdec_vp6f", NULL);
+
+ // Check if the element was correctly created
+ if (!ns->videodecoder) {
+ log_error("A gstreamer flashvideo (VP6) decoder
element could not be created! You probably need to install gst-ffmpeg.");
+ return;
+ }
+
} else if (videoInfo->codec == VIDEO_CODEC_SCREENVIDEO) {
videonincaps = gst_caps_new_simple
("video/x-flash-screen",
"width", G_TYPE_INT, 320, // We don't yet have
a size extract for this codec, so we guess...
@@ -431,6 +475,13 @@
"framerate", GST_TYPE_FRACTION, fps, 1,
NULL);
ns->videodecoder = gst_element_factory_make
("ffdec_flashsv", NULL);
+
+ // Check if the element was correctly created
+ if (!ns->videodecoder) {
+ log_error("A gstreamer flashvideo (ScreenVideo)
decoder element could not be created! You probably need to install
gst-ffmpeg.");
+ return;
+ }
+
} else {
assert(0);
}
@@ -496,19 +547,19 @@
g_signal_connect (ns->videosink, "handoff", G_CALLBACK
(NetStreamGst::callback_output), ns);
if (ns->m_isFLV) {
- if (!ns->videodecoder || !ns->videosource ||
!ns->videoinputcaps || !ns->audiodecoder || !ns->audiosource ||
!ns->audioinputcaps) {
- gnash::log_error("Gstreamer element(s) for video movie
handling could not be created\n");
+ if (!ns->videosource || !ns->audiosource || !ns->videoinputcaps
|| !ns->audioinputcaps) {
+ gnash::log_error("Gstreamer source element(s) for video
movie handling could not be created, you proberly need to install
gstreamer0.10-core for fakesrc and capsfilter support.");
return;
}
} else {
if (!ns->decoder || !ns->source) {
- gnash::log_error("Gstreamer element(s) for video movie
handling could not be created\n");
+ gnash::log_error("Gstreamer element(s) for video movie
handling could not be created, you proberly need to install gstreamer0.10-base
for decodebin support.");
return;
}
}
if (!ns->colorspace || !ns->videocaps || !ns->videorate ||
!ns->videosink) {
- gnash::log_error("Gstreamer element(s) for video movie handling
could not be created\n");
+ gnash::log_error("Gstreamer element(s) for video movie handling
could not be created, you proberly need to install gstreamer0.10-base for
ffmpegcolorspace and videorate support.");
return;
}
@@ -537,6 +588,7 @@
} else {
gst_element_set_state (GST_ELEMENT (ns->pipeline),
GST_STATE_PAUSED);
ns->m_pause = true;
+ ns->m_start_onbuffer = true;
}
ns->set_status("NetStream.Play.Start");
@@ -555,7 +607,7 @@
if (!pipeline) return;
if (m_isFLV) {
- uint32_t newpos =
m_parser->seek(static_cast<uint32_t>(pos*1000))/1000;
+ /*uint32_t newpos =*/
m_parser->seek(static_cast<uint32_t>(pos*1000))/1000;
/*if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET, GST_SECOND *
static_cast<long>(newpos),
GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
@@ -585,21 +637,67 @@
void
NetStreamGst::advance()
{
- if (m_isFLV && m_pause && m_go && !m_imageframe && m_parser &&
m_parser->isTimeLoaded(m_bufferTime)) {
+ // Check if we should start the playback when a certain amount is
buffered
+ if (m_isFLV && m_pause && m_go && m_start_onbuffer && m_parser &&
m_parser->isTimeLoaded(m_bufferTime)) {
set_status("NetStream.Buffer.Full");
m_pause = false;
gst_element_set_state (GST_ELEMENT (pipeline),
GST_STATE_PLAYING);
}
- if (m_statusChanged) {
-/* fn_call dummy(NULL, NULL, 0, 0);
- as_value info_asv(infoobject_new(dummy));
- boost::intrusive_ptr<as_object> info = info_asv.to_object();
+ // If we're out of data, but still not done loading, pause playback,
+ // or stop if loading is complete
+ if (m_pausePlayback) {
+ m_pausePlayback = false;
- fn_call fn(this, v, 0, 0);
+ if (_netCon->loadCompleted()) {
+ set_status("NetStream.Play.Stop");
+ gst_element_set_state (GST_ELEMENT (pipeline),
GST_STATE_NULL);
+ m_go = false;
+ } else {
+ gst_element_set_state (GST_ELEMENT (pipeline),
GST_STATE_PAUSED);
+ GstFormat fmt = GST_FORMAT_TIME;
+ int64_t pos;
+ GstStateChangeReturn ret;
+ GstState current, pending;
- m_statusHandler.get()->call(fn);*/
+ ret = gst_element_get_state (GST_ELEMENT (pipeline),
¤t, &pending, 0);
+ if (current != GST_STATE_NULL &&
gst_element_query_position (pipeline, &fmt, &pos)) {
+ pos = pos / 1000000;
+ } else {
+ pos = 0;
+ }
+ // Buffer a second before continuing
+ m_bufferTime = pos + 1000;
+ m_start_onbuffer = true;
+ m_pause = true;
+ }
+ }
+
+ // Check if there are any new status messages, and if we should
+ // pass them to a event handler
+ as_value status;
+ if (m_statusChanged && get_member(std::string("onStatus"), &status) &&
status.to_as_function() != NULL) {
+
+ for (int i = m_status_messages.size()-1; i >= 0; --i) {
+ boost::intrusive_ptr<as_object> o = new as_object();
+ o->init_member(std::string("code"),
as_value(m_status_messages[i]), 1);
+
+ if (m_status_messages[i].find("StreamNotFound") ==
string::npos && m_status_messages[i].find("InvalidTime") == string::npos) {
+ o->init_member(std::string("level"),
as_value("status"), as_prop_flags::dontDelete|as_prop_flags::dontEnum);
+ } else {
+ o->init_member(std::string("level"),
as_value("error"), as_prop_flags::dontDelete|as_prop_flags::dontEnum);
+ }
+ m_env->push(o.get());
+
+ call_method0(status, m_env, this);
+
+ }
+ m_status_messages.clear();
+ m_statusChanged = false;
+ } else if (m_statusChanged) {
+ m_status_messages.clear();
+ m_statusChanged = false;
}
}
Index: server/asobj/NetStreamGst.h
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/NetStreamGst.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- server/asobj/NetStreamGst.h 28 Mar 2007 16:12:08 -0000 1.10
+++ server/asobj/NetStreamGst.h 30 Mar 2007 13:57:27 -0000 1.11
@@ -55,6 +55,7 @@
bool newFrameReady();
as_function* getStatusHandler();
void setStatusHandler(as_function*);
+ void setEnvironment(as_environment* env);
// Used for gstreamer data read and seek callbacks
static int readPacket(void* opaque, char* buf, int buf_size);
@@ -139,6 +140,18 @@
// The parser for FLV
FLVParser* m_parser;
+
+ // The actionscript enviroment for the AS callbacks
+ as_environment* m_env;
+
+ // On next advance() should we pause?
+ volatile bool m_pausePlayback;
+
+ // List of status messages to be processed
+ std::vector<std::string> m_status_messages;
+
+ // should we start when buffer is full?
+ bool m_start_onbuffer;
};
} // gnash namespace
Index: testsuite/actionscript.all/NetStream.as
===================================================================
RCS file: /sources/gnash/gnash/testsuite/actionscript.all/NetStream.as,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- testsuite/actionscript.all/NetStream.as 30 Mar 2007 10:35:25 -0000
1.9
+++ testsuite/actionscript.all/NetStream.as 30 Mar 2007 13:57:27 -0000
1.10
@@ -20,7 +20,7 @@
// compile this test case with Ming makeswf, and then
// execute it like this gnash -1 -r 0 -v out.swf
-rcsid="$Id: NetStream.as,v 1.9 2007/03/30 10:35:25 strk Exp $";
+rcsid="$Id: NetStream.as,v 1.10 2007/03/30 13:57:27 tgc Exp $";
#include "check.as"
@@ -52,16 +52,24 @@
// SWF7 up is case-sensitive !
check_equals ( typeof(netstreamObj.setbuffertime), 'undefined');
+
check_equals(typeof(netstreamObj.onStatus), 'undefined');
netstreamObj.onStatus = 4;
-xcheck_equals(typeof(netstreamObj.onStatus), 'number');
+check_equals(typeof(netstreamObj.onStatus), 'number');
netstreamObj.onStatus = "str";
-xcheck_equals(typeof(netstreamObj.onStatus), 'string');
+check_equals(typeof(netstreamObj.onStatus), 'string');
+
+check_equals(typeof(netstreamObj.onCuePoint), 'undefined');
+netstreamObj.onCuePoint = 4;
+check_equals(typeof(netstreamObj.onCuePoint), 'number');
+netstreamObj.onCuePoint = "str";
+check_equals(typeof(netstreamObj.onCuePoint), 'string');
+
+check_equals(typeof(netstreamObj.onMetaData), 'undefined');
+netstreamObj.onMetaData = 4;
+check_equals(typeof(netstreamObj.onMetaData), 'number');
+netstreamObj.onMetaData = "str";
+check_equals(typeof(netstreamObj.onMetaData), 'string');
-check_equals(typeof(netstreamObj.onSeek), 'undefined');
-netstreamObj.onSeek = 4;
-check_equals(typeof(netstreamObj.onSeek), 'number');
-netstreamObj.onSeek = "str";
-check_equals(typeof(netstreamObj.onSeek), 'string');
#endif // OUTPUT_VERSION >= 7
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] gnash ChangeLog libbase/FLVParser.cpp libbase/L...,
Tomas Groth <=