2013-11-23 03:36:07 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
2014-01-01 02:37:12 +00:00
|
|
|
Copyright (c) 2013-2014 winlin
|
2013-11-23 03:36:07 +00:00
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
|
|
the Software without restriction, including without limitation the rights to
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2014-03-01 03:24:40 +00:00
|
|
|
#include <srs_protocol_amf0.hpp>
|
2013-11-23 03:36:07 +00:00
|
|
|
|
|
|
|
#include <utility>
|
2014-03-08 15:09:24 +00:00
|
|
|
#include <vector>
|
2014-06-21 03:41:00 +00:00
|
|
|
#include <sstream>
|
2014-03-08 05:11:26 +00:00
|
|
|
using namespace std;
|
2013-11-23 03:36:07 +00:00
|
|
|
|
2014-03-01 02:42:55 +00:00
|
|
|
#include <srs_kernel_log.hpp>
|
2014-03-01 02:30:16 +00:00
|
|
|
#include <srs_kernel_error.hpp>
|
2014-03-01 02:58:13 +00:00
|
|
|
#include <srs_kernel_stream.hpp>
|
2013-11-23 03:36:07 +00:00
|
|
|
|
|
|
|
// AMF0 marker
|
2014-03-18 03:32:58 +00:00
|
|
|
#define RTMP_AMF0_Number 0x00
|
|
|
|
#define RTMP_AMF0_Boolean 0x01
|
|
|
|
#define RTMP_AMF0_String 0x02
|
|
|
|
#define RTMP_AMF0_Object 0x03
|
|
|
|
#define RTMP_AMF0_MovieClip 0x04 // reserved, not supported
|
|
|
|
#define RTMP_AMF0_Null 0x05
|
|
|
|
#define RTMP_AMF0_Undefined 0x06
|
|
|
|
#define RTMP_AMF0_Reference 0x07
|
|
|
|
#define RTMP_AMF0_EcmaArray 0x08
|
|
|
|
#define RTMP_AMF0_ObjectEnd 0x09
|
|
|
|
#define RTMP_AMF0_StrictArray 0x0A
|
|
|
|
#define RTMP_AMF0_Date 0x0B
|
|
|
|
#define RTMP_AMF0_LongString 0x0C
|
|
|
|
#define RTMP_AMF0_UnSupported 0x0D
|
|
|
|
#define RTMP_AMF0_RecordSet 0x0E // reserved, not supported
|
|
|
|
#define RTMP_AMF0_XmlDocument 0x0F
|
|
|
|
#define RTMP_AMF0_TypedObject 0x10
|
2013-11-23 03:36:07 +00:00
|
|
|
// AVM+ object is the AMF3 object.
|
2014-03-18 03:32:58 +00:00
|
|
|
#define RTMP_AMF0_AVMplusObject 0x11
|
2013-11-23 03:36:07 +00:00
|
|
|
// origin array whos data takes the same form as LengthValueBytes
|
2014-03-18 03:32:58 +00:00
|
|
|
#define RTMP_AMF0_OriginStrictArray 0x20
|
2013-11-23 03:36:07 +00:00
|
|
|
|
|
|
|
// User defined
|
2014-03-18 03:32:58 +00:00
|
|
|
#define RTMP_AMF0_Invalid 0x3F
|
2013-11-23 03:36:07 +00:00
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
/**
|
2014-03-08 13:56:14 +00:00
|
|
|
* read amf0 string from stream.
|
|
|
|
* 2.4 String Type
|
|
|
|
* string-type = string-marker UTF-8
|
|
|
|
* @return default value is empty string.
|
|
|
|
* @remark: use SrsAmf0Any::str() to create it.
|
2014-03-08 08:56:35 +00:00
|
|
|
*/
|
2014-03-08 13:56:14 +00:00
|
|
|
class __SrsAmf0String : public SrsAmf0Any
|
2014-03-08 08:56:35 +00:00
|
|
|
{
|
2014-03-08 13:56:14 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
std::string value;
|
|
|
|
|
|
|
|
__SrsAmf0String(const char* _value);
|
|
|
|
virtual ~__SrsAmf0String();
|
|
|
|
|
|
|
|
virtual int total_size();
|
|
|
|
virtual int read(SrsStream* stream);
|
|
|
|
virtual int write(SrsStream* stream);
|
2014-05-29 04:09:26 +00:00
|
|
|
virtual SrsAmf0Any* copy();
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read amf0 boolean from stream.
|
|
|
|
* 2.4 String Type
|
|
|
|
* boolean-type = boolean-marker U8
|
2014-03-18 03:32:58 +00:00
|
|
|
* 0 is false, <> 0 is true
|
2014-03-08 13:56:14 +00:00
|
|
|
* @return default value is false.
|
|
|
|
*/
|
|
|
|
class __SrsAmf0Boolean : public SrsAmf0Any
|
|
|
|
{
|
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
bool value;
|
|
|
|
|
|
|
|
__SrsAmf0Boolean(bool _value);
|
|
|
|
virtual ~__SrsAmf0Boolean();
|
|
|
|
|
|
|
|
virtual int total_size();
|
|
|
|
virtual int read(SrsStream* stream);
|
|
|
|
virtual int write(SrsStream* stream);
|
2014-05-29 04:09:26 +00:00
|
|
|
virtual SrsAmf0Any* copy();
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read amf0 number from stream.
|
|
|
|
* 2.2 Number Type
|
|
|
|
* number-type = number-marker DOUBLE
|
|
|
|
* @return default value is 0.
|
|
|
|
*/
|
|
|
|
class __SrsAmf0Number : public SrsAmf0Any
|
|
|
|
{
|
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
double value;
|
|
|
|
|
|
|
|
__SrsAmf0Number(double _value);
|
|
|
|
virtual ~__SrsAmf0Number();
|
|
|
|
|
|
|
|
virtual int total_size();
|
|
|
|
virtual int read(SrsStream* stream);
|
|
|
|
virtual int write(SrsStream* stream);
|
2014-05-29 04:09:26 +00:00
|
|
|
virtual SrsAmf0Any* copy();
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read amf0 null from stream.
|
|
|
|
* 2.7 null Type
|
|
|
|
* null-type = null-marker
|
|
|
|
*/
|
|
|
|
class __SrsAmf0Null : public SrsAmf0Any
|
|
|
|
{
|
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
__SrsAmf0Null();
|
|
|
|
virtual ~__SrsAmf0Null();
|
|
|
|
|
|
|
|
virtual int total_size();
|
|
|
|
virtual int read(SrsStream* stream);
|
|
|
|
virtual int write(SrsStream* stream);
|
2014-05-29 04:09:26 +00:00
|
|
|
virtual SrsAmf0Any* copy();
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read amf0 undefined from stream.
|
|
|
|
* 2.8 undefined Type
|
|
|
|
* undefined-type = undefined-marker
|
|
|
|
*/
|
|
|
|
class __SrsAmf0Undefined : public SrsAmf0Any
|
|
|
|
{
|
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
__SrsAmf0Undefined();
|
|
|
|
virtual ~__SrsAmf0Undefined();
|
|
|
|
|
|
|
|
virtual int total_size();
|
|
|
|
virtual int read(SrsStream* stream);
|
|
|
|
virtual int write(SrsStream* stream);
|
2014-05-29 04:09:26 +00:00
|
|
|
virtual SrsAmf0Any* copy();
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* to ensure in inserted order.
|
|
|
|
* for the FMLE will crash when AMF0Object is not ordered by inserted,
|
|
|
|
* if ordered in map, the string compare order, the FMLE will creash when
|
|
|
|
* get the response of connect app.
|
|
|
|
*/
|
|
|
|
class __SrsUnSortedHashtable
|
|
|
|
{
|
|
|
|
private:
|
2014-05-18 06:34:45 +00:00
|
|
|
typedef std::pair<std::string, SrsAmf0Any*> SrsAmf0ObjectPropertyType;
|
|
|
|
std::vector<SrsAmf0ObjectPropertyType> properties;
|
2014-03-08 13:56:14 +00:00
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
__SrsUnSortedHashtable();
|
|
|
|
virtual ~__SrsUnSortedHashtable();
|
|
|
|
|
|
|
|
virtual int count();
|
|
|
|
virtual void clear();
|
|
|
|
virtual std::string key_at(int index);
|
2014-05-22 07:08:25 +00:00
|
|
|
virtual const char* key_raw_at(int index);
|
2014-03-18 03:32:58 +00:00
|
|
|
virtual SrsAmf0Any* value_at(int index);
|
|
|
|
virtual void set(std::string key, SrsAmf0Any* value);
|
|
|
|
|
|
|
|
virtual SrsAmf0Any* get_property(std::string name);
|
|
|
|
virtual SrsAmf0Any* ensure_property_string(std::string name);
|
|
|
|
virtual SrsAmf0Any* ensure_property_number(std::string name);
|
2014-05-29 04:09:26 +00:00
|
|
|
|
|
|
|
virtual void copy(__SrsUnSortedHashtable* src);
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 2.11 Object End Type
|
|
|
|
* object-end-type = UTF-8-empty object-end-marker
|
|
|
|
* 0x00 0x00 0x09
|
|
|
|
*/
|
|
|
|
class __SrsAmf0ObjectEOF : public SrsAmf0Any
|
|
|
|
{
|
|
|
|
public:
|
2014-03-18 03:32:58 +00:00
|
|
|
int16_t utf8_empty;
|
|
|
|
|
|
|
|
__SrsAmf0ObjectEOF();
|
|
|
|
virtual ~__SrsAmf0ObjectEOF();
|
|
|
|
|
|
|
|
virtual int total_size();
|
|
|
|
virtual int read(SrsStream* stream);
|
|
|
|
virtual int write(SrsStream* stream);
|
2014-05-29 04:09:26 +00:00
|
|
|
virtual SrsAmf0Any* copy();
|
2014-03-08 13:56:14 +00:00
|
|
|
};
|
2014-03-08 08:56:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* read amf0 utf8 string from stream.
|
|
|
|
* 1.3.1 Strings and UTF-8
|
|
|
|
* UTF-8 = U16 *(UTF8-char)
|
|
|
|
* UTF8-char = UTF8-1 | UTF8-2 | UTF8-3 | UTF8-4
|
|
|
|
* UTF8-1 = %x00-7F
|
|
|
|
* @remark only support UTF8-1 char.
|
|
|
|
*/
|
|
|
|
extern int srs_amf0_read_utf8(SrsStream* stream, std::string& value);
|
|
|
|
extern int srs_amf0_write_utf8(SrsStream* stream, std::string value);
|
|
|
|
|
|
|
|
bool srs_amf0_is_object_eof(SrsStream* stream);
|
2013-11-23 03:36:07 +00:00
|
|
|
int srs_amf0_write_any(SrsStream* stream, SrsAmf0Any* value);
|
|
|
|
|
|
|
|
SrsAmf0Any::SrsAmf0Any()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_Invalid;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsAmf0Any::~SrsAmf0Any()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_string()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_String;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_boolean()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_Boolean;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_number()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_Number;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_null()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_Null;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_undefined()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_Undefined;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_object()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_Object;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_ecma_array()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_EcmaArray;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 08:29:42 +00:00
|
|
|
bool SrsAmf0Any::is_strict_array()
|
|
|
|
{
|
|
|
|
return marker == RTMP_AMF0_StrictArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsAmf0Any::is_complex_object()
|
|
|
|
{
|
|
|
|
return is_object() || is_object_eof() || is_ecma_array() || is_strict_array();
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:13:31 +00:00
|
|
|
string SrsAmf0Any::to_str()
|
2014-03-08 05:57:08 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
__SrsAmf0String* p = dynamic_cast<__SrsAmf0String*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p->value;
|
2014-03-08 05:57:08 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 07:08:25 +00:00
|
|
|
const char* SrsAmf0Any::to_str_raw()
|
|
|
|
{
|
|
|
|
__SrsAmf0String* p = dynamic_cast<__SrsAmf0String*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p->value.data();
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:13:31 +00:00
|
|
|
bool SrsAmf0Any::to_boolean()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
__SrsAmf0Boolean* p = dynamic_cast<__SrsAmf0Boolean*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p->value;
|
2014-03-08 06:13:31 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
double SrsAmf0Any::to_number()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
__SrsAmf0Number* p = dynamic_cast<__SrsAmf0Number*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p->value;
|
2014-03-08 13:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsAmf0Object* SrsAmf0Any::to_object()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsAmf0Object* p = dynamic_cast<SrsAmf0Object*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p;
|
2014-03-08 13:56:14 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:07:40 +00:00
|
|
|
SrsAmf0EcmaArray* SrsAmf0Any::to_ecma_array()
|
2014-03-08 13:56:14 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsAmf0EcmaArray* p = dynamic_cast<SrsAmf0EcmaArray*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p;
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 08:29:42 +00:00
|
|
|
SrsAmf0StrictArray* SrsAmf0Any::to_strict_array()
|
|
|
|
{
|
|
|
|
SrsAmf0StrictArray* p = dynamic_cast<SrsAmf0StrictArray*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
void SrsAmf0Any::set_number(double value)
|
|
|
|
{
|
|
|
|
__SrsAmf0Number* p = dynamic_cast<__SrsAmf0Number*>(this);
|
|
|
|
srs_assert(p != NULL);
|
|
|
|
p->value = value;
|
|
|
|
}
|
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
bool SrsAmf0Any::is_object_eof()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return marker == RTMP_AMF0_ObjectEnd;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-06-21 03:41:00 +00:00
|
|
|
void __srs_fill_level_spaces(stringstream& ss, int level)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < level; i++) {
|
|
|
|
ss << " ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void __srs_amf0_do_print(SrsAmf0Any* any, stringstream& ss, int level)
|
|
|
|
{
|
|
|
|
if (any->is_boolean()) {
|
|
|
|
ss << "Boolean " << (any->to_boolean()? "true":"false") << endl;
|
|
|
|
} else if (any->is_number()) {
|
|
|
|
ss << "Number " << std::fixed << any->to_number() << endl;
|
|
|
|
} else if (any->is_string()) {
|
|
|
|
ss << "String " << any->to_str() << endl;
|
|
|
|
} else if (any->is_null()) {
|
|
|
|
ss << "Null" << endl;
|
|
|
|
} else if (any->is_ecma_array()) {
|
|
|
|
SrsAmf0EcmaArray* obj = any->to_ecma_array();
|
|
|
|
ss << "EcmaArray " << "(" << obj->count() << " items)" << endl;
|
|
|
|
for (int i = 0; i < obj->count(); i++) {
|
|
|
|
__srs_fill_level_spaces(ss, level + 1);
|
|
|
|
ss << "Elem '" << obj->key_at(i) << "' ";
|
|
|
|
if (obj->value_at(i)->is_complex_object()) {
|
|
|
|
__srs_amf0_do_print(obj->value_at(i), ss, level + 1);
|
|
|
|
} else {
|
|
|
|
__srs_amf0_do_print(obj->value_at(i), ss, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (any->is_strict_array()) {
|
|
|
|
SrsAmf0StrictArray* obj = any->to_strict_array();
|
|
|
|
ss << "StrictArray " << "(" << obj->count() << " items)" << endl;
|
|
|
|
for (int i = 0; i < obj->count(); i++) {
|
|
|
|
__srs_fill_level_spaces(ss, level + 1);
|
|
|
|
ss << "Elem ";
|
|
|
|
if (obj->at(i)->is_complex_object()) {
|
|
|
|
__srs_amf0_do_print(obj->at(i), ss, level + 1);
|
|
|
|
} else {
|
|
|
|
__srs_amf0_do_print(obj->at(i), ss, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (any->is_object()) {
|
|
|
|
SrsAmf0Object* obj = any->to_object();
|
|
|
|
ss << "Object " << "(" << obj->count() << " items)" << endl;
|
|
|
|
for (int i = 0; i < obj->count(); i++) {
|
|
|
|
__srs_fill_level_spaces(ss, level + 1);
|
|
|
|
ss << "Property '" << obj->key_at(i) << "' ";
|
|
|
|
if (obj->value_at(i)->is_complex_object()) {
|
|
|
|
__srs_amf0_do_print(obj->value_at(i), ss, level + 1);
|
|
|
|
} else {
|
|
|
|
__srs_amf0_do_print(obj->value_at(i), ss, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ss << "Unknown" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char* SrsAmf0Any::human_print(char** pdata, int* psize)
|
|
|
|
{
|
|
|
|
stringstream ss;
|
|
|
|
|
|
|
|
ss.precision(1);
|
|
|
|
|
|
|
|
__srs_amf0_do_print(this, ss, 0);
|
|
|
|
|
|
|
|
string str = ss.str();
|
|
|
|
if (str.empty()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* data = new char[str.length() + 1];
|
|
|
|
memcpy(data, str.data(), str.length());
|
|
|
|
data[str.length()] = 0;
|
|
|
|
|
|
|
|
if (pdata) {
|
|
|
|
*pdata = data;
|
|
|
|
}
|
|
|
|
if (psize) {
|
|
|
|
*psize = str.length();
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:57:08 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Any::str(const char* value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new __SrsAmf0String(value);
|
2014-03-08 05:57:08 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:13:31 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Any::boolean(bool value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new __SrsAmf0Boolean(value);
|
2014-03-08 05:11:26 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Any::number(double value)
|
2014-03-08 05:11:26 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new __SrsAmf0Number(value);
|
2014-03-08 05:11:26 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Any::null()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new __SrsAmf0Null();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Any::undefined()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new __SrsAmf0Undefined();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 09:04:21 +00:00
|
|
|
SrsAmf0Object* SrsAmf0Any::object()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new SrsAmf0Object();
|
2014-03-08 09:04:21 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Any::object_eof()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new __SrsAmf0ObjectEOF();
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:07:40 +00:00
|
|
|
SrsAmf0EcmaArray* SrsAmf0Any::ecma_array()
|
2014-03-08 09:04:21 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return new SrsAmf0EcmaArray();
|
2014-03-08 09:04:21 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 08:29:42 +00:00
|
|
|
SrsAmf0StrictArray* SrsAmf0Any::strict_array()
|
|
|
|
{
|
|
|
|
return new SrsAmf0StrictArray();
|
|
|
|
}
|
|
|
|
|
2014-03-08 13:06:20 +00:00
|
|
|
int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// detect the object-eof specially
|
|
|
|
if (srs_amf0_is_object_eof(stream)) {
|
|
|
|
*ppvalue = new __SrsAmf0ObjectEOF();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read any marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
srs_verbose("amf0 any marker success");
|
|
|
|
|
|
|
|
// backward the 1byte marker.
|
|
|
|
stream->skip(-1);
|
|
|
|
|
|
|
|
switch (marker) {
|
|
|
|
case RTMP_AMF0_String: {
|
|
|
|
*ppvalue = SrsAmf0Any::str();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case RTMP_AMF0_Boolean: {
|
|
|
|
*ppvalue = SrsAmf0Any::boolean();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case RTMP_AMF0_Number: {
|
|
|
|
*ppvalue = SrsAmf0Any::number();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case RTMP_AMF0_Null: {
|
|
|
|
*ppvalue = SrsAmf0Any::null();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case RTMP_AMF0_Undefined: {
|
|
|
|
*ppvalue = SrsAmf0Any::undefined();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case RTMP_AMF0_Object: {
|
|
|
|
*ppvalue = SrsAmf0Any::object();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case RTMP_AMF0_EcmaArray: {
|
|
|
|
*ppvalue = SrsAmf0Any::ecma_array();
|
|
|
|
return ret;
|
|
|
|
}
|
2014-05-22 08:29:42 +00:00
|
|
|
case RTMP_AMF0_StrictArray: {
|
|
|
|
*ppvalue = SrsAmf0Any::strict_array();
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
case RTMP_AMF0_Invalid:
|
|
|
|
default: {
|
|
|
|
ret = ERROR_RTMP_AMF0_INVALID;
|
|
|
|
srs_error("invalid amf0 message type. marker=%#x, ret=%d", marker, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 13:06:20 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
__SrsUnSortedHashtable::__SrsUnSortedHashtable()
|
2014-03-08 05:11:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
__SrsUnSortedHashtable::~__SrsUnSortedHashtable()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-05-29 04:09:26 +00:00
|
|
|
clear();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsUnSortedHashtable::count()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return (int)properties.size();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
void __SrsUnSortedHashtable::clear()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-05-29 04:09:26 +00:00
|
|
|
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
|
|
|
|
for (it = properties.begin(); it != properties.end(); ++it) {
|
|
|
|
SrsAmf0ObjectPropertyType& elem = *it;
|
|
|
|
SrsAmf0Any* any = elem.second;
|
|
|
|
srs_freep(any);
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
properties.clear();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
string __SrsUnSortedHashtable::key_at(int index)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_assert(index < count());
|
2014-05-18 06:34:45 +00:00
|
|
|
SrsAmf0ObjectPropertyType& elem = properties[index];
|
2014-03-18 03:32:58 +00:00
|
|
|
return elem.first;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 07:08:25 +00:00
|
|
|
const char* __SrsUnSortedHashtable::key_raw_at(int index)
|
|
|
|
{
|
|
|
|
srs_assert(index < count());
|
|
|
|
SrsAmf0ObjectPropertyType& elem = properties[index];
|
|
|
|
return elem.first.data();
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
SrsAmf0Any* __SrsUnSortedHashtable::value_at(int index)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_assert(index < count());
|
2014-05-18 06:34:45 +00:00
|
|
|
SrsAmf0ObjectPropertyType& elem = properties[index];
|
2014-03-18 03:32:58 +00:00
|
|
|
return elem.second;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
void __SrsUnSortedHashtable::set(string key, SrsAmf0Any* value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
if (!value) {
|
|
|
|
srs_warn("add a NULL propertity %s", key.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-18 06:34:45 +00:00
|
|
|
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
for (it = properties.begin(); it != properties.end(); ++it) {
|
2014-05-18 06:34:45 +00:00
|
|
|
SrsAmf0ObjectPropertyType& elem = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
std::string name = elem.first;
|
|
|
|
SrsAmf0Any* any = elem.second;
|
|
|
|
|
|
|
|
if (key == name) {
|
|
|
|
srs_freep(any);
|
|
|
|
properties.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
properties.push_back(std::make_pair(key, value));
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* __SrsUnSortedHashtable::get_property(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-05-18 06:34:45 +00:00
|
|
|
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
for (it = properties.begin(); it != properties.end(); ++it) {
|
2014-05-18 06:34:45 +00:00
|
|
|
SrsAmf0ObjectPropertyType& elem = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
std::string key = elem.first;
|
|
|
|
SrsAmf0Any* any = elem.second;
|
|
|
|
if (key == name) {
|
|
|
|
return any;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* __SrsUnSortedHashtable::ensure_property_string(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsAmf0Any* prop = get_property(name);
|
|
|
|
|
|
|
|
if (!prop) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!prop->is_string()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return prop;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* __SrsUnSortedHashtable::ensure_property_number(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
SrsAmf0Any* prop = get_property(name);
|
|
|
|
|
|
|
|
if (!prop) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!prop->is_number()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return prop;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
void __SrsUnSortedHashtable::copy(__SrsUnSortedHashtable* src)
|
|
|
|
{
|
|
|
|
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
|
|
|
|
for (it = src->properties.begin(); it != src->properties.end(); ++it) {
|
|
|
|
SrsAmf0ObjectPropertyType& elem = *it;
|
|
|
|
std::string key = elem.first;
|
|
|
|
SrsAmf0Any* any = elem.second;
|
|
|
|
set(key, any->copy());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
__SrsAmf0ObjectEOF::__SrsAmf0ObjectEOF()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_ObjectEnd;
|
|
|
|
utf8_empty = 0x00;
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__SrsAmf0ObjectEOF::~__SrsAmf0ObjectEOF()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsAmf0ObjectEOF::total_size()
|
2014-03-08 06:38:19 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return SrsAmf0Size::object_eof();
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
int __SrsAmf0ObjectEOF::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(2)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read object eof value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int16_t temp = stream->read_2bytes();
|
|
|
|
if (temp != 0x00) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read object eof value check failed. "
|
|
|
|
"must be 0x00, actual is %#x, ret=%d", temp, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read object eof marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_ObjectEnd) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check object eof marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_ObjectEnd, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read object eof marker success");
|
|
|
|
|
|
|
|
srs_verbose("amf0 read object eof success");
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
int __SrsAmf0ObjectEOF::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(2)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write object eof value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
stream->write_2bytes(0x00);
|
|
|
|
srs_verbose("amf0 write object eof value success");
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write object eof marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_ObjectEnd);
|
|
|
|
|
|
|
|
srs_verbose("amf0 read object eof success");
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* __SrsAmf0ObjectEOF::copy()
|
|
|
|
{
|
|
|
|
return new __SrsAmf0ObjectEOF();
|
|
|
|
}
|
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
SrsAmf0Object::SrsAmf0Object()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
properties = new __SrsUnSortedHashtable();
|
|
|
|
eof = new __SrsAmf0ObjectEOF();
|
|
|
|
marker = RTMP_AMF0_Object;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsAmf0Object::~SrsAmf0Object()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(properties);
|
|
|
|
srs_freep(eof);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int SrsAmf0Object::total_size()
|
2014-03-08 14:51:13 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int size = 1;
|
|
|
|
|
|
|
|
for (int i = 0; i < properties->count(); i++){
|
|
|
|
std::string name = key_at(i);
|
|
|
|
SrsAmf0Any* value = value_at(i);
|
|
|
|
|
|
|
|
size += SrsAmf0Size::utf8(name);
|
|
|
|
size += SrsAmf0Size::any(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
size += SrsAmf0Size::object_eof();
|
|
|
|
|
|
|
|
return size;
|
2014-03-08 14:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 05:11:26 +00:00
|
|
|
int SrsAmf0Object::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read object marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_Object) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check object marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read object marker success");
|
|
|
|
|
|
|
|
// value
|
|
|
|
while (!stream->empty()) {
|
|
|
|
// detect whether is eof.
|
|
|
|
if (srs_amf0_is_object_eof(stream)) {
|
|
|
|
__SrsAmf0ObjectEOF pbj_eof;
|
|
|
|
if ((ret = pbj_eof.read(stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 object read eof failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("amf0 read object EOF.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// property-name: utf8 string
|
|
|
|
std::string property_name;
|
|
|
|
if ((ret =srs_amf0_read_utf8(stream, property_name)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 object read property name failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
// property-value: any
|
|
|
|
SrsAmf0Any* property_value = NULL;
|
|
|
|
if ((ret = srs_amf0_read_any(stream, &property_value)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 object read property_value failed. "
|
|
|
|
"name=%s, ret=%d", property_name.c_str(), ret);
|
|
|
|
srs_freep(property_value);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add property
|
|
|
|
this->set(property_name, property_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 05:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Object::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write object marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_Object);
|
|
|
|
srs_verbose("amf0 write object marker success");
|
|
|
|
|
|
|
|
// value
|
|
|
|
for (int i = 0; i < properties->count(); i++) {
|
|
|
|
std::string name = this->key_at(i);
|
|
|
|
SrsAmf0Any* any = this->value_at(i);
|
|
|
|
|
|
|
|
if ((ret = srs_amf0_write_utf8(stream, name)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write object property name failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = srs_amf0_write_any(stream, any)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write object property value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("write amf0 property success. name=%s", name.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = eof->write(stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write object eof failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("write amf0 object success.");
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 05:11:26 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Object::copy()
|
|
|
|
{
|
|
|
|
SrsAmf0Object* copy = new SrsAmf0Object();
|
|
|
|
copy->properties->copy(properties);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
void SrsAmf0Object::clear()
|
|
|
|
{
|
|
|
|
properties->clear();
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:51:13 +00:00
|
|
|
int SrsAmf0Object::count()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->count();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
string SrsAmf0Object::key_at(int index)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->key_at(index);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 07:08:25 +00:00
|
|
|
const char* SrsAmf0Object::key_raw_at(int index)
|
|
|
|
{
|
|
|
|
return properties->key_raw_at(index);
|
|
|
|
}
|
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Object::value_at(int index)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->value_at(index);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
void SrsAmf0Object::set(string key, SrsAmf0Any* value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
properties->set(key, value);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Object::get_property(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->get_property(name);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Object::ensure_property_string(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->ensure_property_string(name);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* SrsAmf0Object::ensure_property_number(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->ensure_property_number(name);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 05:11:26 +00:00
|
|
|
SrsAmf0EcmaArray::SrsAmf0EcmaArray()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-05-29 04:09:26 +00:00
|
|
|
_count = 0;
|
2014-03-18 03:32:58 +00:00
|
|
|
properties = new __SrsUnSortedHashtable();
|
|
|
|
eof = new __SrsAmf0ObjectEOF();
|
|
|
|
marker = RTMP_AMF0_EcmaArray;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 05:11:26 +00:00
|
|
|
SrsAmf0EcmaArray::~SrsAmf0EcmaArray()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(properties);
|
|
|
|
srs_freep(eof);
|
2014-03-08 05:11:26 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int SrsAmf0EcmaArray::total_size()
|
2014-03-08 14:51:13 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int size = 1 + 4;
|
|
|
|
|
|
|
|
for (int i = 0; i < properties->count(); i++){
|
|
|
|
std::string name = key_at(i);
|
|
|
|
SrsAmf0Any* value = value_at(i);
|
|
|
|
|
|
|
|
size += SrsAmf0Size::utf8(name);
|
|
|
|
size += SrsAmf0Size::any(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
size += SrsAmf0Size::object_eof();
|
|
|
|
|
|
|
|
return size;
|
2014-03-08 14:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 05:11:26 +00:00
|
|
|
int SrsAmf0EcmaArray::read(SrsStream* stream)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read ecma_array marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_EcmaArray) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check ecma_array marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read ecma_array marker success");
|
|
|
|
|
|
|
|
// count
|
|
|
|
if (!stream->require(4)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read ecma_array count failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t count = stream->read_4bytes();
|
|
|
|
srs_verbose("amf0 read ecma_array count success. count=%d", count);
|
|
|
|
|
|
|
|
// value
|
|
|
|
this->_count = count;
|
|
|
|
|
|
|
|
while (!stream->empty()) {
|
|
|
|
// detect whether is eof.
|
|
|
|
if (srs_amf0_is_object_eof(stream)) {
|
|
|
|
__SrsAmf0ObjectEOF pbj_eof;
|
|
|
|
if ((ret = pbj_eof.read(stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 ecma_array read eof failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("amf0 read ecma_array EOF.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// property-name: utf8 string
|
|
|
|
std::string property_name;
|
|
|
|
if ((ret =srs_amf0_read_utf8(stream, property_name)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 ecma_array read property name failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
// property-value: any
|
|
|
|
SrsAmf0Any* property_value = NULL;
|
|
|
|
if ((ret = srs_amf0_read_any(stream, &property_value)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 ecma_array read property_value failed. "
|
|
|
|
"name=%s, ret=%d", property_name.c_str(), ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add property
|
|
|
|
this->set(property_name, property_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
2014-03-08 05:11:26 +00:00
|
|
|
int SrsAmf0EcmaArray::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write ecma_array marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_EcmaArray);
|
|
|
|
srs_verbose("amf0 write ecma_array marker success");
|
|
|
|
|
|
|
|
// count
|
|
|
|
if (!stream->require(4)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write ecma_array count failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_4bytes(this->_count);
|
|
|
|
srs_verbose("amf0 write ecma_array count success. count=%d", _count);
|
|
|
|
|
|
|
|
// value
|
|
|
|
for (int i = 0; i < properties->count(); i++) {
|
|
|
|
std::string name = this->key_at(i);
|
|
|
|
SrsAmf0Any* any = this->value_at(i);
|
|
|
|
|
|
|
|
if ((ret = srs_amf0_write_utf8(stream, name)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write ecma_array property name failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = srs_amf0_write_any(stream, any)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write ecma_array property value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("write amf0 property success. name=%s", name.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = eof->write(stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write ecma_array eof failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("write ecma_array object success.");
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 05:11:26 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* SrsAmf0EcmaArray::copy()
|
|
|
|
{
|
|
|
|
SrsAmf0EcmaArray* copy = new SrsAmf0EcmaArray();
|
|
|
|
copy->properties->copy(properties);
|
|
|
|
copy->_count = _count;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:51:13 +00:00
|
|
|
void SrsAmf0EcmaArray::clear()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
properties->clear();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:51:13 +00:00
|
|
|
int SrsAmf0EcmaArray::count()
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->count();
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
string SrsAmf0EcmaArray::key_at(int index)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->key_at(index);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 07:08:25 +00:00
|
|
|
const char* SrsAmf0EcmaArray::key_raw_at(int index)
|
|
|
|
{
|
|
|
|
return properties->key_raw_at(index);
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:11:26 +00:00
|
|
|
SrsAmf0Any* SrsAmf0EcmaArray::value_at(int index)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->value_at(index);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
void SrsAmf0EcmaArray::set(string key, SrsAmf0Any* value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
properties->set(key, value);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* SrsAmf0EcmaArray::get_property(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->get_property(name);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* SrsAmf0EcmaArray::ensure_property_string(string name)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->ensure_property_string(name);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
SrsAmf0Any* SrsAmf0EcmaArray::ensure_property_number(string name)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return properties->ensure_property_number(name);
|
2014-03-08 15:09:24 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 08:29:42 +00:00
|
|
|
SrsAmf0StrictArray::SrsAmf0StrictArray()
|
|
|
|
{
|
|
|
|
marker = RTMP_AMF0_StrictArray;
|
2014-06-07 12:01:11 +00:00
|
|
|
_count = 0;
|
2014-05-22 08:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsAmf0StrictArray::~SrsAmf0StrictArray()
|
|
|
|
{
|
|
|
|
std::vector<SrsAmf0Any*>::iterator it;
|
|
|
|
for (it = properties.begin(); it != properties.end(); ++it) {
|
|
|
|
SrsAmf0Any* any = *it;
|
|
|
|
srs_freep(any);
|
|
|
|
}
|
|
|
|
properties.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0StrictArray::total_size()
|
|
|
|
{
|
|
|
|
int size = 1 + 4;
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)properties.size(); i++){
|
|
|
|
SrsAmf0Any* any = properties[i];
|
|
|
|
size += any->total_size();
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0StrictArray::read(SrsStream* stream)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read strict_array marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_StrictArray) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check strict_array marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read strict_array marker success");
|
|
|
|
|
|
|
|
// count
|
|
|
|
if (!stream->require(4)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read strict_array count failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t count = stream->read_4bytes();
|
|
|
|
srs_verbose("amf0 read strict_array count success. count=%d", count);
|
|
|
|
|
|
|
|
// value
|
|
|
|
this->_count = count;
|
|
|
|
|
|
|
|
for (int i = 0; i < count && !stream->empty(); i++) {
|
|
|
|
// property-value: any
|
|
|
|
SrsAmf0Any* elem = NULL;
|
|
|
|
if ((ret = srs_amf0_read_any(stream, &elem)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 strict_array read value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add property
|
|
|
|
properties.push_back(elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int SrsAmf0StrictArray::write(SrsStream* stream)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write strict_array marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_StrictArray);
|
|
|
|
srs_verbose("amf0 write strict_array marker success");
|
|
|
|
|
|
|
|
// count
|
|
|
|
if (!stream->require(4)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write strict_array count failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_4bytes(this->_count);
|
|
|
|
srs_verbose("amf0 write strict_array count success. count=%d", _count);
|
|
|
|
|
|
|
|
// value
|
|
|
|
for (int i = 0; i < (int)properties.size(); i++) {
|
|
|
|
SrsAmf0Any* any = properties[i];
|
|
|
|
|
|
|
|
if ((ret = srs_amf0_write_any(stream, any)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("write strict_array property value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("write amf0 property success. name=%s", name.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("write strict_array object success.");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* SrsAmf0StrictArray::copy()
|
|
|
|
{
|
|
|
|
SrsAmf0StrictArray* copy = new SrsAmf0StrictArray();
|
|
|
|
|
|
|
|
std::vector<SrsAmf0Any*>::iterator it;
|
|
|
|
for (it = properties.begin(); it != properties.end(); ++it) {
|
|
|
|
SrsAmf0Any* any = *it;
|
|
|
|
copy->append(any->copy());
|
|
|
|
}
|
|
|
|
|
|
|
|
copy->_count = _count;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-05-22 08:29:42 +00:00
|
|
|
void SrsAmf0StrictArray::clear()
|
|
|
|
{
|
|
|
|
properties.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0StrictArray::count()
|
|
|
|
{
|
|
|
|
return properties.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsAmf0Any* SrsAmf0StrictArray::at(int index)
|
|
|
|
{
|
|
|
|
srs_assert(index < (int)properties.size());
|
|
|
|
return properties.at(index);
|
|
|
|
}
|
|
|
|
|
2014-05-28 11:01:47 +00:00
|
|
|
void SrsAmf0StrictArray::append(SrsAmf0Any* any)
|
|
|
|
{
|
|
|
|
properties.push_back(any);
|
2014-05-29 04:09:26 +00:00
|
|
|
_count = (int32_t)properties.size();
|
2014-05-28 11:01:47 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 05:41:15 +00:00
|
|
|
int SrsAmf0Size::utf8(string value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 2 + value.length();
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::str(string value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 1 + SrsAmf0Size::utf8(value);
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::number()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 1 + 8;
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::null()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 1;
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::undefined()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 1;
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::boolean()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 1 + 1;
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::object(SrsAmf0Object* obj)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
if (!obj) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj->total_size();
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsAmf0Size::object_eof()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return 2 + 1;
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 14:07:40 +00:00
|
|
|
int SrsAmf0Size::ecma_array(SrsAmf0EcmaArray* arr)
|
2014-03-08 05:41:15 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
if (!arr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return arr->total_size();
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 08:29:42 +00:00
|
|
|
int SrsAmf0Size::strict_array(SrsAmf0StrictArray* arr)
|
|
|
|
{
|
|
|
|
if (!arr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return arr->total_size();
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:41:15 +00:00
|
|
|
int SrsAmf0Size::any(SrsAmf0Any* o)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
if (!o) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return o->total_size();
|
2014-03-08 05:41:15 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:13:31 +00:00
|
|
|
__SrsAmf0String::__SrsAmf0String(const char* _value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_String;
|
|
|
|
if (_value) {
|
|
|
|
value = _value;
|
|
|
|
}
|
2014-03-08 06:13:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__SrsAmf0String::~__SrsAmf0String()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsAmf0String::total_size()
|
2014-03-08 06:13:31 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return SrsAmf0Size::str(value);
|
2014-03-08 06:13:31 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
int __SrsAmf0String::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_read_string(stream, value);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __SrsAmf0String::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_write_string(stream, value);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* __SrsAmf0String::copy()
|
|
|
|
{
|
|
|
|
__SrsAmf0String* copy = new __SrsAmf0String(value.c_str());
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:13:31 +00:00
|
|
|
__SrsAmf0Boolean::__SrsAmf0Boolean(bool _value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_Boolean;
|
|
|
|
value = _value;
|
2014-03-08 06:13:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__SrsAmf0Boolean::~__SrsAmf0Boolean()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsAmf0Boolean::total_size()
|
2014-03-08 06:13:31 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return SrsAmf0Size::boolean();
|
2014-03-08 06:13:31 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
int __SrsAmf0Boolean::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_read_boolean(stream, value);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __SrsAmf0Boolean::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_write_boolean(stream, value);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* __SrsAmf0Boolean::copy()
|
|
|
|
{
|
|
|
|
__SrsAmf0Boolean* copy = new __SrsAmf0Boolean(value);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
__SrsAmf0Number::__SrsAmf0Number(double _value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_Number;
|
|
|
|
value = _value;
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__SrsAmf0Number::~__SrsAmf0Number()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsAmf0Number::total_size()
|
2014-03-08 06:38:19 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return SrsAmf0Size::number();
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
int __SrsAmf0Number::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_read_number(stream, value);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __SrsAmf0Number::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_write_number(stream, value);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* __SrsAmf0Number::copy()
|
|
|
|
{
|
|
|
|
__SrsAmf0Number* copy = new __SrsAmf0Number(value);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
__SrsAmf0Null::__SrsAmf0Null()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_Null;
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__SrsAmf0Null::~__SrsAmf0Null()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsAmf0Null::total_size()
|
2014-03-08 06:38:19 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return SrsAmf0Size::null();
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
int __SrsAmf0Null::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_read_null(stream);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __SrsAmf0Null::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_write_null(stream);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* __SrsAmf0Null::copy()
|
|
|
|
{
|
|
|
|
__SrsAmf0Null* copy = new __SrsAmf0Null();
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
__SrsAmf0Undefined::__SrsAmf0Undefined()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
marker = RTMP_AMF0_Undefined;
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__SrsAmf0Undefined::~__SrsAmf0Undefined()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-08 14:59:30 +00:00
|
|
|
int __SrsAmf0Undefined::total_size()
|
2014-03-08 06:38:19 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return SrsAmf0Size::undefined();
|
2014-03-08 06:38:19 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
int __SrsAmf0Undefined::read(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_read_undefined(stream);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __SrsAmf0Undefined::write(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return srs_amf0_write_undefined(stream);
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:09:26 +00:00
|
|
|
SrsAmf0Any* __SrsAmf0Undefined::copy()
|
|
|
|
{
|
|
|
|
__SrsAmf0Undefined* copy = new __SrsAmf0Undefined();
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2014-03-08 13:06:20 +00:00
|
|
|
int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any** ppvalue)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if ((ret = SrsAmf0Any::discovery(stream, ppvalue)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 discovery any elem failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_assert(*ppvalue);
|
|
|
|
|
|
|
|
if ((ret = (*ppvalue)->read(stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("amf0 parse elem failed. ret=%d", ret);
|
|
|
|
srs_freep(*ppvalue);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2014-03-08 13:06:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int srs_amf0_write_any(SrsStream* stream, SrsAmf0Any* value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_assert(value != NULL);
|
|
|
|
return value->write(stream);
|
2014-03-08 13:06:20 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
int srs_amf0_read_utf8(SrsStream* stream, string& value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// len
|
|
|
|
if (!stream->require(2)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read string length failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int16_t len = stream->read_2bytes();
|
|
|
|
srs_verbose("amf0 read string length success. len=%d", len);
|
|
|
|
|
|
|
|
// empty string
|
|
|
|
if (len <= 0) {
|
|
|
|
srs_verbose("amf0 read empty string. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// data
|
|
|
|
if (!stream->require(len)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read string data failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
std::string str = stream->read_string(len);
|
|
|
|
|
|
|
|
// support utf8-1 only
|
|
|
|
// 1.3.1 Strings and UTF-8
|
|
|
|
// UTF8-1 = %x00-7F
|
|
|
|
// TODO: support other utf-8 strings
|
|
|
|
/*for (int i = 0; i < len; i++) {
|
|
|
|
char ch = *(str.data() + i);
|
|
|
|
if ((ch & 0x80) != 0) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("ignored. only support utf8-1, 0x00-0x7F, actual is %#x. ret=%d", (int)ch, ret);
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
value = str;
|
|
|
|
srs_verbose("amf0 read string data success. str=%s", str.c_str());
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
2014-03-08 15:09:24 +00:00
|
|
|
int srs_amf0_write_utf8(SrsStream* stream, string value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// len
|
|
|
|
if (!stream->require(2)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write string length failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
stream->write_2bytes(value.length());
|
|
|
|
srs_verbose("amf0 write string length success. len=%d", (int)value.length());
|
|
|
|
|
|
|
|
// empty string
|
|
|
|
if (value.length() <= 0) {
|
|
|
|
srs_verbose("amf0 write empty string. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// data
|
|
|
|
if (!stream->require(value.length())) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write string data failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
stream->write_string(value);
|
|
|
|
srs_verbose("amf0 write string data success. str=%s", value.c_str());
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
int srs_amf0_read_string(SrsStream* stream, string& value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read string marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_String) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check string marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_String, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read string marker success");
|
|
|
|
|
|
|
|
return srs_amf0_read_utf8(stream, value);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 15:09:24 +00:00
|
|
|
int srs_amf0_write_string(SrsStream* stream, string value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write string marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_String);
|
|
|
|
srs_verbose("amf0 write string marker success");
|
|
|
|
|
|
|
|
return srs_amf0_write_utf8(stream, value);
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int srs_amf0_read_boolean(SrsStream* stream, bool& value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read bool marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_Boolean) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check bool marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Boolean, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read bool marker success");
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read bool value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream->read_1bytes() == 0) {
|
|
|
|
value = false;
|
|
|
|
} else {
|
|
|
|
value = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("amf0 read bool value success. value=%d", value);
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
int srs_amf0_write_boolean(SrsStream* stream, bool value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write bool marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
stream->write_1bytes(RTMP_AMF0_Boolean);
|
|
|
|
srs_verbose("amf0 write bool marker success");
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write bool value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
stream->write_1bytes(0x01);
|
|
|
|
} else {
|
|
|
|
stream->write_1bytes(0x00);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_verbose("amf0 write bool value success. value=%d", value);
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int srs_amf0_read_number(SrsStream* stream, double& value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read number marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_Number) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check number marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Number, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read number marker success");
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(8)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read number value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t temp = stream->read_8bytes();
|
|
|
|
memcpy(&value, &temp, 8);
|
|
|
|
|
|
|
|
srs_verbose("amf0 read number value success. value=%.2f", value);
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
int srs_amf0_write_number(SrsStream* stream, double value)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write number marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_Number);
|
|
|
|
srs_verbose("amf0 write number marker success");
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(8)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write number value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t temp = 0x00;
|
|
|
|
memcpy(&temp, &value, 8);
|
|
|
|
stream->write_8bytes(temp);
|
|
|
|
|
|
|
|
srs_verbose("amf0 write number value success. value=%.2f", value);
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int srs_amf0_read_null(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read null marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_Null) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check null marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Null, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read null success");
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
int srs_amf0_write_null(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write null marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_Null);
|
|
|
|
srs_verbose("amf0 write null marker success");
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int srs_amf0_read_undefined(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 read undefined marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char marker = stream->read_1bytes();
|
|
|
|
if (marker != RTMP_AMF0_Undefined) {
|
|
|
|
ret = ERROR_RTMP_AMF0_DECODE;
|
|
|
|
srs_error("amf0 check undefined marker failed. "
|
|
|
|
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Undefined, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("amf0 read undefined success");
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
int srs_amf0_write_undefined(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write undefined marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_Undefined);
|
|
|
|
srs_verbose("amf0 write undefined marker success");
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 08:56:35 +00:00
|
|
|
bool srs_amf0_is_object_eof(SrsStream* stream)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
// detect the object-eof specially
|
|
|
|
if (stream->require(3)) {
|
|
|
|
int32_t flag = stream->read_3bytes();
|
|
|
|
stream->skip(-3);
|
|
|
|
|
|
|
|
return 0x09 == flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2014-03-08 08:56:35 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 06:38:19 +00:00
|
|
|
int srs_amf0_write_object_eof(SrsStream* stream, __SrsAmf0ObjectEOF* value)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
srs_assert(value != NULL);
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (!stream->require(2)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write object eof value failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
stream->write_2bytes(0x00);
|
|
|
|
srs_verbose("amf0 write object eof value success");
|
|
|
|
|
|
|
|
// marker
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AMF0_ENCODE;
|
|
|
|
srs_error("amf0 write object eof marker failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->write_1bytes(RTMP_AMF0_ObjectEnd);
|
|
|
|
|
|
|
|
srs_verbose("amf0 read object eof success");
|
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|