diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 32c0cb9fc..48f97d8bb 100755 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -43,5 +43,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define srs_assert(expression) assert(expression) #include +#include #endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_amf0.cpp b/trunk/src/core/srs_core_amf0.cpp index 34d3c049d..89cd500f5 100755 --- a/trunk/src/core/srs_core_amf0.cpp +++ b/trunk/src/core/srs_core_amf0.cpp @@ -49,23 +49,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // origin array whos data takes the same form as LengthValueBytes #define RTMP_AMF0_OriginStrictArray 0x20 -std::string srs_amf0_read_string(SrsStream* stream) +std::string srs_amf0_read_utf8(SrsStream* stream) { std::string str; - // marker - if (!stream->require(1)) { - srs_warn("amf0 read string marker failed"); - return str; - } - - char marker = stream->read_char(); - if (marker != RTMP_AMF0_String) { - srs_warn("amf0 check string marker failed. marker=%#x, required=%#x", marker, RTMP_AMF0_String); - return str; - } - srs_verbose("amf0 read string marker success"); - // len if (!stream->require(2)) { srs_warn("amf0 read string length failed"); @@ -74,6 +61,12 @@ std::string srs_amf0_read_string(SrsStream* stream) 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."); + return str; + } + // data if (!stream->require(len)) { srs_warn("amf0 read string data failed"); @@ -96,8 +89,125 @@ std::string srs_amf0_read_string(SrsStream* stream) return str; } -double srs_amf0_read_number(SrsStream* stream) +std::string srs_amf0_read_string(SrsStream* stream) { - return 0; + // marker + if (!stream->require(1)) { + srs_warn("amf0 read string marker failed"); + return ""; + } + + char marker = stream->read_char(); + if (marker != RTMP_AMF0_String) { + srs_warn("amf0 check string marker failed. marker=%#x, required=%#x", marker, RTMP_AMF0_String); + return ""; + } + srs_verbose("amf0 read string marker success"); + + return srs_amf0_read_utf8(stream); } +double srs_amf0_read_number(SrsStream* stream) +{ + double value = 0; + + // marker + if (!stream->require(1)) { + srs_warn("amf0 read number marker failed"); + return value; + } + + char marker = stream->read_char(); + if (marker != RTMP_AMF0_Number) { + srs_warn("amf0 check number marker failed. marker=%#x, required=%#x", marker, RTMP_AMF0_Number); + return value; + } + srs_verbose("amf0 read number marker success"); + + // value + if (!stream->require(8)) { + srs_warn("amf0 read number value failed"); + return value; + } + + int64_t temp = stream->read_8bytes(); + memcpy(&value, &temp, 8); + + srs_verbose("amf0 read number value success. value=%.2f", value); + + return value; +} + +SrsAmf0Object* srs_amf0_read_object(SrsStream* stream) +{ + SrsAmf0Object* value = NULL; + return value; +} + +SrsAmf0Any::SrsAmf0Any() +{ + marker = RTMP_AMF0_Null; +} + +SrsAmf0Any::~SrsAmf0Any() +{ +} + +bool SrsAmf0Any::is_string() +{ + return marker == RTMP_AMF0_String; +} + +bool SrsAmf0Any::is_number() +{ + return marker == RTMP_AMF0_Number; +} + +bool SrsAmf0Any::is_object() +{ + return marker == RTMP_AMF0_Object; +} + +SrsAmf0String::SrsAmf0String() +{ + marker = RTMP_AMF0_String; +} + +SrsAmf0String::~SrsAmf0String() +{ +} + +SrsAmf0Number::SrsAmf0Number() +{ + marker = RTMP_AMF0_Number; + value = 0; +} + +SrsAmf0Number::~SrsAmf0Number() +{ +} + +SrsAmf0ObjectEOF::SrsAmf0ObjectEOF() +{ + utf8_empty = 0x00; + object_end_marker = RTMP_AMF0_ObjectEnd; +} + +SrsAmf0ObjectEOF::~SrsAmf0ObjectEOF() +{ +} + +SrsAmf0Object::SrsAmf0Object() +{ + marker = RTMP_AMF0_Object; +} + +SrsAmf0Object::~SrsAmf0Object() +{ + std::map::iterator it; + for (it = properties.begin(); it != properties.end(); ++it) { + SrsAmf0Any* any = it->second; + delete any; + } + properties.clear(); +} diff --git a/trunk/src/core/srs_core_amf0.hpp b/trunk/src/core/srs_core_amf0.hpp index 44c207c5b..8cdd8b1d1 100755 --- a/trunk/src/core/srs_core_amf0.hpp +++ b/trunk/src/core/srs_core_amf0.hpp @@ -31,13 +31,27 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include class SrsStream; +class SrsAmf0Object; + +/** +* 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. +* @return default value is empty string. +*/ +extern std::string srs_amf0_read_utf8(SrsStream* stream); /** * read amf0 string from stream. * 2.4 String Type * string-type = string-marker UTF-8 +* @return default value is empty string. */ extern std::string srs_amf0_read_string(SrsStream* stream); @@ -45,7 +59,106 @@ extern std::string srs_amf0_read_string(SrsStream* stream); * read amf0 number from stream. * 2.2 Number Type * number-type = number-marker DOUBLE +* @return default value is 0. */ extern double srs_amf0_read_number(SrsStream* stream); +/** +* read amf0 object from stream. +* 2.5 Object Type +* anonymous-object-type = object-marker *(object-property) +* object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) +*/ +extern SrsAmf0Object* srs_amf0_read_object(SrsStream* stream); + +/** +* any amf0 value. +* 2.1 Types Overview +* value-type = number-type | boolean-type | string-type | object-type +* | null-marker | undefined-marker | reference-type | ecma-array-type +* | strict-array-type | date-type | long-string-type | xml-document-type +* | typed-object-type +*/ +struct SrsAmf0Any +{ + char marker; + + SrsAmf0Any(); + virtual ~SrsAmf0Any(); + + virtual bool is_string(); + virtual bool is_number(); + virtual bool is_object(); + + /** + * convert the any to specified object. + * @return T*, the converted object. never NULL. + * @remark, user must ensure the current object type, + * or the covert will cause assert failed. + */ + template + T* convert() + { + T* p = dynamic_cast(this); + srs_assert(p != NULL); + return p; + } +}; + +/** +* read amf0 string from stream. +* 2.4 String Type +* string-type = string-marker UTF-8 +* @return default value is empty string. +*/ +struct SrsAmf0String : public SrsAmf0Any +{ + std::string value; + + SrsAmf0String(); + virtual ~SrsAmf0String(); +}; + +/** +* read amf0 number from stream. +* 2.2 Number Type +* number-type = number-marker DOUBLE +* @return default value is 0. +*/ +struct SrsAmf0Number : public SrsAmf0Any +{ + double value; + + SrsAmf0Number(); + virtual ~SrsAmf0Number(); +}; + +/** +* 2.11 Object End Type +* object-end-type = UTF-8-empty object-end-marker +* 0x00 0x00 0x09 +*/ +struct SrsAmf0ObjectEOF +{ + int16_t utf8_empty; + char object_end_marker; + + SrsAmf0ObjectEOF(); + virtual ~SrsAmf0ObjectEOF(); +}; + +/** +* 2.5 Object Type +* anonymous-object-type = object-marker *(object-property) +* object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) +*/ +struct SrsAmf0Object : public SrsAmf0Any +{ + std::map properties; + SrsAmf0ObjectEOF eof; + + SrsAmf0Object(); + virtual ~SrsAmf0Object(); +}; + #endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_protocol.cpp b/trunk/src/core/srs_core_protocol.cpp index 08934ed64..ba5f54da3 100755 --- a/trunk/src/core/srs_core_protocol.cpp +++ b/trunk/src/core/srs_core_protocol.cpp @@ -320,6 +320,9 @@ int SrsPacket::decode(SrsStream* /*stream*/) SrsConnectAppPacket::SrsConnectAppPacket() { + command_name = RTMP_AMF0_COMMAND_CONNECT; + transaction_id = 1; + command_object = NULL; } SrsConnectAppPacket::~SrsConnectAppPacket() @@ -335,9 +338,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream) } command_name = srs_amf0_read_string(stream); - if (command_name.empty()) { + if (command_name.empty() || command_name != RTMP_AMF0_COMMAND_CONNECT) { ret = ERROR_RTMP_AMF0_DECODE; - srs_error("amf0 decode connect command_name failed. ret=%d", ret); + srs_error("amf0 decode connect command_name failed. " + "command_name=%s, ret=%d", command_name.c_str(), ret); return ret; } @@ -349,6 +353,15 @@ int SrsConnectAppPacket::decode(SrsStream* stream) return ret; } + command_object = srs_amf0_read_object(stream); + if (command_object == NULL) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 decode connect command_object failed. ret=%d", ret); + return ret; + } + + srs_info("amf0 decode connect packet success"); + return ret; } diff --git a/trunk/src/core/srs_core_protocol.hpp b/trunk/src/core/srs_core_protocol.hpp index 16a52c92d..b25ffb5a7 100755 --- a/trunk/src/core/srs_core_protocol.hpp +++ b/trunk/src/core/srs_core_protocol.hpp @@ -44,6 +44,7 @@ class SrsPacket; class SrsStream; class SrsMessage; class SrsChunkStream; +class SrsAmf0Object; /** * 4.1. Message Header @@ -164,6 +165,7 @@ private: private: std::string command_name; double transaction_id; + SrsAmf0Object* command_object; public: SrsConnectAppPacket(); virtual ~SrsConnectAppPacket(); diff --git a/trunk/src/core/srs_core_stream.cpp b/trunk/src/core/srs_core_stream.cpp index 5a90e4b8f..eb9066a3c 100755 --- a/trunk/src/core/srs_core_stream.cpp +++ b/trunk/src/core/srs_core_stream.cpp @@ -92,6 +92,24 @@ int16_t SrsStream::read_2bytes() return value; } +int64_t SrsStream::read_8bytes() +{ + srs_assert(require(8)); + + int64_t value; + pp = (char*)&value; + pp[7] = *p++; + pp[6] = *p++; + pp[5] = *p++; + pp[4] = *p++; + pp[3] = *p++; + pp[2] = *p++; + pp[1] = *p++; + pp[0] = *p++; + + return value; +} + std::string SrsStream::read_string(int len) { srs_assert(require(len)); diff --git a/trunk/src/core/srs_core_stream.hpp b/trunk/src/core/srs_core_stream.hpp index aa6ed92fa..5206e5045 100755 --- a/trunk/src/core/srs_core_stream.hpp +++ b/trunk/src/core/srs_core_stream.hpp @@ -75,6 +75,10 @@ public: */ virtual int16_t read_2bytes(); /** + * get 8bytes int from stream. + */ + virtual int64_t read_8bytes(); + /** * get string from stream, length specifies by param len. */ virtual std::string read_string(int len);