gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r9662: add tag interface to MediaPar


From: Sandro Santilli
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r9662: add tag interface to MediaParser; implement it in FLVParser and use from NetStreamFfmpeg
Date: Wed, 03 Sep 2008 02:05:38 +0200
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 9662
committer: Sandro Santilli <address@hidden>
branch nick: trunk
timestamp: Wed 2008-09-03 02:05:38 +0200
message:
  add tag interface to MediaParser; implement it in FLVParser and use from 
NetStreamFfmpeg
modified:
  libcore/Makefile.am
  libcore/as_value.cpp
  libcore/as_value.h
  libcore/asobj/NetConnection.cpp
  libcore/asobj/NetStreamFfmpeg.cpp
  libmedia/FLVParser.cpp
  libmedia/FLVParser.h
  libmedia/MediaParser.cpp
  libmedia/MediaParser.h
  testsuite/misc-ming.all/NetStream-SquareTest.c
    ------------------------------------------------------------
    revno: 9659.1.1
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Tue 2008-09-02 18:26:29 +0200
    message:
      Add support for ECMA array (objects) to amf0 to as_value converter.
      Fully qualify amf namespace.
    modified:
      libcore/asobj/NetConnection.cpp
    ------------------------------------------------------------
    revno: 9659.1.2
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Wed 2008-09-03 00:20:43 +0200
    message:
      add support for decoding bool amf0
    modified:
      libcore/asobj/NetConnection.cpp
    ------------------------------------------------------------
    revno: 9659.1.3
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Wed 2008-09-03 00:57:53 +0200
    message:
      Move AMF0 to as_value conversion from NetConnection to as_value;
      add interface of MediaParser to process tags; implement tags processing
      in FLVParser by executing custom methods; fixes NetStream-SquareTest
      with ffmpeg.
    modified:
      libcore/Makefile.am
      libcore/as_value.cpp
      libcore/as_value.h
      libcore/asobj/NetConnection.cpp
      libcore/asobj/NetStreamFfmpeg.cpp
      libmedia/FLVParser.cpp
      libmedia/FLVParser.h
      libmedia/MediaParser.cpp
      libmedia/MediaParser.h
      testsuite/misc-ming.all/NetStream-SquareTest.c
    ------------------------------------------------------------
    revno: 9659.1.4
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Wed 2008-09-03 01:15:48 +0200
    message:
      make FLV metatags access thread-safe
    modified:
      libmedia/FLVParser.cpp
      libmedia/FLVParser.h
    ------------------------------------------------------------
    revno: 9659.1.5
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Wed 2008-09-03 01:28:53 +0200
    message:
      drop unneeded double decoding of FLV metatag
    modified:
      libmedia/FLVParser.cpp
    ------------------------------------------------------------
    revno: 9659.1.6
    committer: Sandro Santilli <address@hidden>
    branch nick: mybranch
    timestamp: Wed 2008-09-03 01:43:00 +0200
    message:
      hush amf parsing verbosity with compile-time macro
    modified:
      libcore/as_value.cpp
=== modified file 'libcore/Makefile.am'
--- a/libcore/Makefile.am       2008-08-18 23:53:04 +0000
+++ b/libcore/Makefile.am       2008-09-02 22:57:53 +0000
@@ -38,6 +38,7 @@
        -I$(top_srcdir)/libcore/vm \
        -I$(top_srcdir)/libbase \
        -I$(top_srcdir)/libmedia \
+       -I$(top_srcdir)/libamf \
        $(PTHREAD_CFLAGS) \
        $(DMALLOC_CFLAGS) \
        $(GLIB_CFLAGS) \

=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp      2008-09-01 18:11:06 +0000
+++ b/libcore/as_value.cpp      2008-09-02 23:43:00 +0000
@@ -32,6 +32,10 @@
 #include "action.h" // for call_method0
 #include "utility.h" // for typeName() and utility::isFinite
 #include "namedStrings.h"
+#include "element.h" // for readAMF
+#include "amf.h" // for readAMF
+#include "array.h" // for readAMF
+#include "Object.h" // for readAMF
 
 #include <cmath> // std::fmod
 #include <boost/algorithm/string/case_conv.hpp>
@@ -50,6 +54,9 @@
 // Define this macro to make soft references activity verbose
 //#define GNASH_DEBUG_SOFT_REFERENCES
 
+// Define this macto to make AMF parsing verbose
+//#define GNASH_DEBUG_AMF_PARSING
+
 namespace {
 
 struct invalidHexDigit {};
@@ -1746,6 +1753,207 @@
        return *this;
 }
 
+
+static boost::uint16_t
+readNetworkShort(const boost::uint8_t* buf) {
+       boost::uint16_t s = buf[0] << 8 | buf[1];
+       return s;
+}
+
+static boost::uint16_t
+readNetworkLong(const boost::uint8_t* buf) {
+       boost::uint32_t s = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+       return s;
+}
+
+// Pass pointer to buffer and pointer to end of buffer. Buffer is raw AMF
+// encoded data. Must start with a type byte unless third parameter is set.
+//
+// On success, sets the given as_value and returns true.
+// On error (premature end of buffer, etc.) returns false and leaves the given
+// as_value untouched.
+//
+// IF you pass a fourth parameter, it WILL NOT READ A TYPE BYTE, but use what
+// you passed instead.
+//
+// The l-value you pass as the first parameter (buffer start) is updated to
+// point just past the last byte parsed
+//
+// TODO restore first parameter on parse errors
+//
+static bool
+amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end, as_value& ret, int 
inType = -1)
+{
+       boost::uint16_t si;
+       boost::uint16_t li;
+       double dub;
+       int amf_type;
+
+       if(b > end) {
+               return false;
+       }
+       if(inType != -1) {
+               amf_type = inType;
+       } else {
+               if(b < end) {
+                       amf_type = *b; b += 1;
+               } else {
+                       return false;
+               }
+       }
+
+       switch(amf_type) {
+               case amf::Element::BOOLEAN_AMF0:
+               {
+                       bool val = *b; b += 1;
+#ifdef GNASH_DEBUG_AMF_PARSING
+                       log_debug("amf0 read bool: %d", val);
+#endif
+                       ret.set_bool(val);
+                       return true;
+               }
+               case amf::Element::NUMBER_AMF0:
+                       if(b + 8 > end) {
+                               log_error(_("AMF0 read: premature end of input 
reading Number type"));
+                               return false;
+                       }
+                       dub = *(reinterpret_cast<double*>(b)); b += 8;
+                       amf::swapBytes(&dub, 8);
+#ifdef GNASH_DEBUG_AMF_PARSING
+                       log_debug("amf0 read double: %e", dub);
+#endif
+                       ret.set_double(dub);
+                       return true;
+               case amf::Element::STRING_AMF0:
+                       if(b + 2 > end) {
+                               log_error(_("AMF0 read: premature end of input 
reading String type"));
+                               return false;
+                       }
+                       si = readNetworkShort(b); b += 2;
+                       if(b + si > end) {
+                               log_error(_("AMF0 read: premature end of input 
reading String type"));
+                               return false;
+                       }
+
+                       {
+                               std::string str(reinterpret_cast<char *>(b), 
si); b += si;
+#ifdef GNASH_DEBUG_AMF_PARSING
+                               log_debug("amf0 read string: %s", str);
+#endif
+                               ret.set_string(str);
+                               return true;
+
+                       }
+                       break;
+               case amf::Element::STRICT_ARRAY_AMF0:
+                       {
+                               boost::intrusive_ptr<as_array_object> array(new 
as_array_object());
+                               li = readNetworkLong(b); b += 4;
+#ifdef GNASH_DEBUG_AMF_PARSING
+                               log_debug("amf0 starting read of array with %i 
elements", li);
+#endif
+                               as_value arrayElement;
+                               for(int i = 0; i < li; ++i)
+                               {
+                                       if ( ! amf0_read_value(b, end, 
arrayElement) )
+                                       {
+                                               return false;
+                                       }
+                                       array->push(arrayElement);
+                               }
+
+                               ret.set_as_object(array);
+                               return true;
+                       }
+               case amf::Element::ECMA_ARRAY_AMF0:
+                       {
+                               boost::intrusive_ptr<as_object> obj(new 
as_object(getObjectInterface()));
+                               li = readNetworkLong(b); b += 4;
+#ifdef GNASH_DEBUG_AMF_PARSING
+                               log_debug("amf0 starting read of object with %i 
elements", li);
+#endif
+                               as_value objectElement;
+                               VM& vm = VM::get(); // TODO: get VM from outside
+                               string_table& st = vm.getStringTable();
+                               for(int i = 0; i < li; ++i)
+                               {
+                                       boost::uint16_t strlen = 
readNetworkShort(b); b+=2; 
+                                       std::string name((char*)b, strlen);
+#ifdef GNASH_DEBUG_AMF_PARSING
+                                       log_debug("amf0 Object prop name is 
%s", name);
+#endif
+                                       b += strlen;
+                                       if ( ! amf0_read_value(b, end, 
objectElement) )
+                                       {
+                                               return false;
+                                       }
+                                       obj->set_member(st.find(name), 
objectElement);
+                               }
+
+                               ret.set_as_object(obj);
+                               return true;
+                       }
+               case amf::Element::OBJECT_AMF0:
+                       {
+                               // TODO: need this? 
boost::intrusive_ptr<as_object> obj(new as_object(getObjectInterface()));
+                               boost::intrusive_ptr<as_object> obj(new 
as_object());
+#ifdef GNASH_DEBUG_AMF_PARSING
+                               log_debug("amf0 starting read of object");
+#endif
+                               as_value tmp;
+                               std::string keyString;
+                               for(;;)
+                               {
+                                       if ( ! amf0_read_value(b, end, tmp, 
amf::Element::STRING_AMF0) )
+                                       {
+                                               return false;
+                                       }
+                                       keyString = tmp.to_string();
+
+                                       if ( keyString.empty() )
+                                       {
+                                               if(b < end) {
+                                                       b += 1; // AMF0 has a 
redundant "object end" byte
+                                               } else {
+                                                       log_error("AMF buffer 
terminated just before object end byte. continueing anyway.");
+                                               }
+                                               ret.set_as_object(obj);
+                                               return true;
+                                       }
+
+                                       if ( ! amf0_read_value(b, end, tmp) )
+                                       {
+                                               return false;
+                                       }
+                                       obj->init_member(keyString, tmp);
+                               }
+                       }
+               case amf::Element::UNDEFINED_AMF0:
+                       {
+                               ret.set_undefined();
+                               return true;
+                       }
+               case amf::Element::NULL_AMF0:
+                       {
+                               ret.set_null();
+                               return true;
+                       }
+               // TODO define other types (function, sprite, etc)
+               default:
+                       log_unimpl("AMF0 to as_value: unsupported type: %i", 
amf_type);
+                       return false;
+       }
+
+       // this function was called with a zero-length buffer
+       return false;
+}
+
+bool
+as_value::readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType)
+{
+       return amf0_read_value(b, end, *this, inType);
+}
+
 } // namespace gnash
 
 

=== modified file 'libcore/as_value.h'
--- a/libcore/as_value.h        2008-08-29 08:59:12 +0000
+++ b/libcore/as_value.h        2008-09-02 22:57:53 +0000
@@ -176,6 +176,25 @@
        /// Construct a NULL or AS_FUNCTION value
        as_value(as_function* func);
 
+       /// Read AMF0 data from the given buffer
+       //
+       /// Pass pointer to buffer and pointer to end of buffer. Buffer is raw 
AMF
+       /// encoded data. Must start with a type byte unless third parameter is 
set.
+       ///
+       /// On success, sets the given as_value and returns true.
+       /// On error (premature end of buffer, etc.) returns false and leaves 
the given
+       /// as_value untouched.
+       ///
+       /// IF you pass a fourth parameter, it WILL NOT READ A TYPE BYTE, but 
use what
+       /// you passed instead.
+       ///
+       /// The l-value you pass as the first parameter (buffer start) is 
updated to
+       /// point just past the last byte parsed
+       ///
+       /// TODO restore first parameter on parse errors
+       ///
+       bool readAMF0(boost::uint8_t *&b, boost::uint8_t *end, int inType = -1);
+
        /// Convert numeric value to string value, following ECMA-262 
specification
        //
        /// TODO: move here some of the good comments found in the function 
definition.

=== modified file 'libcore/asobj/NetConnection.cpp'
--- a/libcore/asobj/NetConnection.cpp   2008-08-29 08:45:10 +0000
+++ b/libcore/asobj/NetConnection.cpp   2008-09-02 22:57:53 +0000
@@ -25,6 +25,7 @@
 #include <iostream>
 #include <string>
 #include <boost/scoped_ptr.hpp>
+#include <arpa/inet.h> // for htons
 
 #include "NetConnection.h"
 #include "log.h"
@@ -39,13 +40,13 @@
 
 // for NetConnection.call()
 #include "VM.h"
-#include "array.h"
+//#include "array.h"
 #include "amf.h"
 #include "SimpleBuffer.h"
 #include "timers.h"
 #include "namedStrings.h"
 
-using namespace amf;
+//using namespace amf;
 
 namespace gnash {
 
@@ -192,156 +193,18 @@
        return as_value();
 }
 
-boost::uint16_t
+static boost::uint16_t
 readNetworkShort(const boost::uint8_t* buf) {
        boost::uint16_t s = buf[0] << 8 | buf[1];
        return s;
 }
 
-boost::uint16_t
+static boost::uint16_t
 readNetworkLong(const boost::uint8_t* buf) {
        boost::uint32_t s = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
        return s;
 }
 
-// Pass pointer to buffer and pointer to end of buffer. Buffer is raw AMF
-// encoded data. Must start with a type byte unless third parameter is set.
-//
-// On success, sets the given as_value and returns true.
-// On error (premature end of buffer, etc.) returns false and leaves the given
-// as_value untouched.
-//
-// IF you pass a fourth parameter, it WILL NOT READ A TYPE BYTE, but use what
-// you passed instead.
-//
-// The l-value you pass as the first parameter (buffer start) is updated to
-// point just past the last byte parsed
-//
-// TODO restore first parameter on parse errors
-//
-static bool
-amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end, as_value& ret, int 
inType = -1)
-{
-       boost::uint16_t si;
-       boost::uint16_t li;
-       double dub;
-       int amf_type;
-
-       if(b > end) {
-               return false;
-       }
-       if(inType != -1) {
-               amf_type = inType;
-       } else {
-               if(b < end) {
-                       amf_type = *b; b += 1;
-               } else {
-                       return false;
-               }
-       }
-
-       switch(amf_type) {
-               case Element::NUMBER_AMF0:
-                       if(b + 8 > end) {
-                               log_error(_("NetConnection.call(): server sent 
us a number which goes past the end of the data sent"));
-                               return false;
-                       }
-                       dub = *(reinterpret_cast<double*>(b)); b += 8;
-                       swapBytes(&dub, 8);
-                       log_debug("nc read double: %e", dub);
-                       ret.set_double(dub);
-                       return true;
-               case Element::STRING_AMF0:
-                       if(b + 2 > end) {
-                               log_error(_("NetConnection.call(): server sent 
us a string which goes past the end of the data sent"));
-                               return false;
-                       }
-                       si = readNetworkShort(b); b += 2;
-                       if(b + si > end) {
-                               log_error(_("NetConnection.call(): server sent 
us a string which goes past the end of the data sent"));
-                               return false;
-                       }
-
-                       {
-                               std::string str(reinterpret_cast<char *>(b), 
si); b += si;
-                               log_debug("nc read string: %s", str);
-                               ret.set_string(str);
-                               return true;
-
-                       }
-                       break;
-               case Element::STRICT_ARRAY_AMF0:
-                       {
-                               boost::intrusive_ptr<as_array_object> array(new 
as_array_object());
-                               li = readNetworkLong(b); b += 4;
-                               log_debug("nc starting read of array with %i 
elements", li);
-                               as_value arrayElement;
-                               for(int i = 0; i < li; ++i)
-                               {
-                                       if ( ! amf0_read_value(b, end, 
arrayElement) )
-                                       {
-                                               return false;
-                                       }
-                                       array->push(arrayElement);
-                               }
-
-                               ret.set_as_object(array);
-                               return true;
-                       }
-               case Element::OBJECT_AMF0:
-                       {
-                               // need this? boost::intrusive_ptr<as_object> 
obj(new as_object(getObjectInterface()));
-                               boost::intrusive_ptr<as_object> obj(new 
as_object());
-                               log_debug("nc starting read of object");
-                               as_value tmp;
-                               std::string keyString;
-                               for(;;)
-                               {
-                                       if ( ! amf0_read_value(b, end, tmp, 
Element::STRING_AMF0) )
-                                       {
-                                               return false;
-                                       }
-                                       keyString = tmp.to_string();
-
-                                       if ( keyString.empty() )
-                                       {
-                                               if(b < end) {
-                                                       b += 1; // AMF0 has a 
redundant "object end" byte
-                                               } else {
-                                                       log_error("AMF buffer 
terminated just before object end byte. continueing anyway.");
-                                               }
-                                               ret.set_as_object(obj);
-                                               return true;
-                                       }
-
-                                       if ( ! amf0_read_value(b, end, tmp) )
-                                       {
-                                               return false;
-                                       }
-                                       obj->init_member(keyString, tmp);
-                               }
-                       }
-               case Element::UNDEFINED_AMF0:
-                       {
-                               ret.set_undefined();
-                               return true;
-                       }
-               case Element::NULL_AMF0:
-                       {
-                               ret.set_null();
-                               return true;
-                       }
-               // TODO define other types (function, sprite, etc)
-               default:
-                       log_unimpl("NetConnection.call(): server sent us a 
value of unsupported type: %i", amf_type);
-                       return false;
-       }
-
-       // this function was called with a zero-length buffer
-       return false;
-}
-
-
 /// Queue of remoting calls 
 //
 /// This class in made to handle data and do defered processing for
@@ -479,7 +342,7 @@
                                                                break;
                                                        }
                                                        std::string 
headerName((char*)b, si); // end-b);
-                                                       //if( 
!amf0_read_value(b, end, tmp) )
+                                                       //if( !tmp.readAMF0(b, 
end) )
                                                        //{
                                                        //      headers_ok = 0;
                                                        //      break;
@@ -491,7 +354,7 @@
                                                                break;
                                                        }
                                                        b += 5; // skip past 
bool and length long
-                                                       if( !amf0_read_value(b, 
end, tmp) )
+                                                       if( !tmp.readAMF0(b, 
end) )
                                                        {
                                                                headers_ok = 0;
                                                                break;
@@ -549,7 +412,7 @@
                                                                
log_debug("about to parse amf value");
                                                                // this updates 
b to point to the next unparsed byte
                                                                as_value 
reply_as_value;
-                                                               if ( ! 
amf0_read_value(b, end, reply_as_value) )
+                                                               if ( ! 
reply_as_value.readAMF0(b, end) )
                                                                {
                                                                        
log_error("parse amf failed");
                                                                        // this 
will happen if we get
@@ -746,14 +609,14 @@
 
 
        // encode array of arguments to remote method
-       buf->appendByte(Element::STRICT_ARRAY_AMF0);
+       buf->appendByte(amf::Element::STRICT_ARRAY_AMF0);
        buf->appendNetworkLong(fn.nargs - 2);
        if (fn.nargs > 2) {
 
                for (unsigned int i = 2; i < fn.nargs; ++i) {
 
                        if (fn.arg(i).is_string()) {
-                               buf->appendByte(Element::STRING_AMF0);
+                               buf->appendByte(amf::Element::STRING_AMF0);
                                std::string str = fn.arg(i).to_string();
                                buf->appendNetworkShort(str.size());
                                buf->append(str.c_str(), str.size());
@@ -765,8 +628,8 @@
 
                        else if(fn.arg(i).is_number()) {
                                double d = fn.arg(i).to_number();
-                               buf->appendByte(Element::NUMBER_AMF0);
-                               swapBytes(&d, 8); // this actually only swapps 
on little-endian machines
+                               buf->appendByte(amf::Element::NUMBER_AMF0);
+                               amf::swapBytes(&d, 8); // this actually only 
swapps on little-endian machines
                                buf->append(&d, 8);
                        // FIXME implement this
                        //} else if(fn.arg(i).is_object()) {
@@ -776,7 +639,7 @@
                        
                        else {
                                log_error(_("NetConnection.call(): unknown 
argument type"));
-                               buf->appendByte(Element::UNDEFINED_AMF0);
+                               buf->appendByte(amf::Element::UNDEFINED_AMF0);
                        }
                }
        }

=== modified file 'libcore/asobj/NetStreamFfmpeg.cpp'
--- a/libcore/asobj/NetStreamFfmpeg.cpp 2008-09-01 13:10:41 +0000
+++ b/libcore/asobj/NetStreamFfmpeg.cpp 2008-09-02 22:57:53 +0000
@@ -995,6 +995,9 @@
        // Refill audio buffer to consume all samples
        // up to current playhead
        refreshAudioBuffer();
+
+       // Process media tags
+       m_parser->processTags(_playHead.getPosition(), this, getVM());
 }
 
 boost::int32_t

=== modified file 'libmedia/FLVParser.cpp'
--- a/libmedia/FLVParser.cpp    2008-09-02 09:37:42 +0000
+++ b/libmedia/FLVParser.cpp    2008-09-02 23:28:53 +0000
@@ -26,6 +26,12 @@
 #include "utility.h"
 #include "GnashException.h"
 #include "IOChannel.h"
+#include "SimpleBuffer.h"
+
+#include "as_object.h"
+#include "array.h"
+#include "element.h"
+#include "VM.h"
 
 #include <string>
 #include <iosfwd>
@@ -60,7 +66,10 @@
 
 FLVParser::~FLVParser()
 {
-       // nothing to do here, all done in base class now
+       for (MetaTags::iterator i=_metaTags.begin(), e=_metaTags.end(); i!=e; 
++i)
+       {
+               delete *i;
+       }
 }
 
 
@@ -447,18 +456,18 @@
        else if (tag[0] == FLV_META_TAG)
        {
                // Extract information from the meta tag
-               boost::scoped_array<unsigned char> metaTag ( new unsigned 
char[bodyLength] );
-               size_t actuallyRead = _stream->read(metaTag.get(), bodyLength);
+               std::auto_ptr<SimpleBuffer> metaTag(new 
SimpleBuffer(bodyLength));
+               size_t actuallyRead = _stream->read(metaTag->data(), 
bodyLength);
                if ( actuallyRead < bodyLength )
                {
                        log_error("FLVParser::parseNextTag: can't read metaTag 
(%d) body (needed %d bytes, only got %d)",
                                FLV_META_TAG, bodyLength, actuallyRead);
                        return false;
                }
-                amf::Flv flv;
-                std::auto_ptr<amf::Element> el ( 
flv.decodeMetaData(metaTag.get(), actuallyRead) );
-               log_unimpl("FLV MetaTag handling. Data: %s", *el);
-                //el->dump();
+               metaTag->resize(actuallyRead);
+
+               boost::mutex::scoped_lock lock(_metaTagsMutex);
+               _metaTags.push_back(new MetaTag(timestamp, metaTag));
        }
        else
        {
@@ -574,6 +583,59 @@
        return frame;
 }
 
+void
+FLVParser::processTags(boost::uint64_t ts, as_object* thisPtr, VM& vm)
+{
+       boost::mutex::scoped_lock lock(_metaTagsMutex);
+       while (!_metaTags.empty())
+       {
+               if ( _metaTags.front()->timestamp() > ts ) break;
+
+               std::auto_ptr<MetaTag> tag ( _metaTags.front() );
+               _metaTags.pop_front();
+               tag->execute(thisPtr, vm);
+               
+       }
+}
+
+void
+FLVParser::MetaTag::execute(as_object* thisPtr, VM& vm)
+{
+       boost::uint8_t* ptr = _buffer->data();
+       boost::uint8_t* endptr = ptr+_buffer->size();
+
+       //log_debug("FLV meta: %s", hexify(ptr, 32, 0));
+       //log_debug("FLV meta: %s", hexify(ptr, 32, 1));
+
+       if ( ptr + 2 > endptr ) {
+               log_error("Premature end of AMF in FLV metatag");
+               return;
+       }
+       boost::uint16_t length = ntohs((*(boost::uint16_t *)ptr) & 0xffff);
+       ptr+=2;
+
+       if ( ptr + length > endptr ) {
+               log_error("Premature end of AMF in FLV metatag");
+               return;
+       }
+       std::string funcName((char*)ptr, length); // TODO: check for OOB !
+       ptr += length;
+
+       log_debug("funcName: %s", funcName);
+
+       string_table& st = vm.getStringTable();
+       string_table::key funcKey = st.find(funcName);
+
+       as_value arg;
+       if ( ! arg.readAMF0(ptr, endptr) )
+       {
+               log_error("Could not convert FLV metatag to as_value");
+               return;
+       }
+
+       thisPtr->callMethod(funcKey, arg);
+}
+
 } // end of gnash::media namespace
 } // end of gnash namespace
 

=== modified file 'libmedia/FLVParser.h'
--- a/libmedia/FLVParser.h      2008-09-02 10:00:19 +0000
+++ b/libmedia/FLVParser.h      2008-09-02 23:15:48 +0000
@@ -25,6 +25,7 @@
 
 #include "dsodefs.h"
 #include "MediaParser.h" // for inheritance
+#include "SimpleBuffer.h" // for MetaTag destructor
 
 #include <vector>
 #include <memory>
@@ -32,6 +33,12 @@
 
 #include <boost/thread/mutex.hpp>
 
+// Forward declarations
+namespace gnash {
+       class as_object;
+       class VM;
+}
+
 namespace gnash {
 namespace media {
 
@@ -77,6 +84,8 @@
                return _indexingCompleted;
        }
 
+       virtual void processTags(boost::uint64_t ts, as_object* thisPtr, VM& 
env);
+
 private:
 
        /// Parses next tag from the file
@@ -132,6 +141,25 @@
        CuePointsMap _cuePoints;
 
        bool _indexingCompleted;
+
+       class MetaTag {
+       public:
+               MetaTag(boost::uint64_t t, std::auto_ptr<SimpleBuffer> b)
+                       :
+                       _timestamp(t),
+                       _buffer(b)
+               {}
+
+               void execute(as_object* thisPtr, VM& env);
+               boost::uint64_t timestamp() const { return _timestamp; }
+       private:
+               boost::uint64_t _timestamp;
+               std::auto_ptr<SimpleBuffer> _buffer;
+       };
+
+       typedef std::deque<MetaTag*> MetaTags;
+       MetaTags _metaTags;
+       boost::mutex _metaTagsMutex;
 };
 
 } // end of gnash::media namespace

=== modified file 'libmedia/MediaParser.cpp'
--- a/libmedia/MediaParser.cpp  2008-09-02 10:11:27 +0000
+++ b/libmedia/MediaParser.cpp  2008-09-02 22:57:53 +0000
@@ -359,6 +359,12 @@
        }
 }
 
+
+void
+MediaParser::processTags(boost::uint64_t /*ts*/, as_object* /*thisPtr*/, VM& 
/*env*/)
+{
+}
+
 std::ostream& operator << (std::ostream& os, const VideoInfo& vi)
 {
        os << "codec:" << vi.codec << " (type " << vi.type << ") - "

=== modified file 'libmedia/MediaParser.h'
--- a/libmedia/MediaParser.h    2008-09-02 10:11:27 +0000
+++ b/libmedia/MediaParser.h    2008-09-02 22:57:53 +0000
@@ -38,6 +38,12 @@
 #define LOAD_MEDIA_IN_A_SEPARATE_THREAD 1
 
 
+// Forward declarations
+namespace gnash {
+       class as_object;
+       class VM;
+}
+
 namespace gnash {
 namespace media {
 
@@ -390,6 +396,8 @@
        ///
        virtual bool parseNextChunk()=0;
 
+       virtual void processTags(boost::uint64_t ts, as_object* thisPtr, VM& 
env);
+
 protected:
 
        /// Start the parser thread

=== modified file 'testsuite/misc-ming.all/NetStream-SquareTest.c'
--- a/testsuite/misc-ming.all/NetStream-SquareTest.c    2008-06-17 13:04:17 
+0000
+++ b/testsuite/misc-ming.all/NetStream-SquareTest.c    2008-09-02 22:57:53 
+0000
@@ -506,7 +506,7 @@
                //      and would succeed in composition checking in second 
call.
                " if ( _root.metadataNotified > 1 ) return;"
 
-               " xcheck(_root.startNotified, 'onMetaData should be notified 
after Play.Start');"
+               " check(_root.startNotified, 'onMetaData should be notified 
after Play.Start');"
                " check_equals(arguments.length, 1, 'single argument');"
                " check(info instanceof Object, 'onMetaData argument should be 
instanceof Object');"
 
@@ -515,7 +515,7 @@
                " for (e in info) { "
                "  enu.push(e);"
                " }"
-               " xcheck_equals(enu.length, 11);" // gnash contains 2 more 
+               " check_equals(enu.length, 11);" // gnash contains 2 more 
 
                "\n"
 
@@ -609,10 +609,10 @@
 
   SWFMovie_nextFrame(mo);
 
-  xcheck_equals(mo, "metadataNotified", "1");
+  check_equals(mo, "metadataNotified", "1");
   check_equals(mo, "stopNotified", "2");
   check_equals(mo, "startNotified", "1");
-  SWFMovie_add(mo, (SWFBlock)newSWFAction("totals(119); stop();"));
+  SWFMovie_add(mo, (SWFBlock)newSWFAction("totals(140); stop();"));
 
   SWFMovie_nextFrame(mo);
 


reply via email to

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