gnash-commit
[Top][All Lists]
Advanced

[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), 
&current, &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




reply via email to

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