mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
connect vhost/app packet decoded.
This commit is contained in:
parent
2886672347
commit
df400ef1c5
6 changed files with 324 additions and 59 deletions
|
@ -24,6 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_core_amf0.hpp>
|
||||
|
||||
#include <srs_core_log.hpp>
|
||||
#include <srs_core_error.hpp>
|
||||
#include <srs_core_stream.hpp>
|
||||
|
||||
// AMF0 marker
|
||||
|
@ -49,30 +50,34 @@ 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_utf8(SrsStream* stream)
|
||||
int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*&);
|
||||
|
||||
int srs_amf0_read_utf8(SrsStream* stream, std::string& value)
|
||||
{
|
||||
std::string str;
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// len
|
||||
if (!stream->require(2)) {
|
||||
srs_warn("amf0 read string length failed");
|
||||
return str;
|
||||
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.");
|
||||
return str;
|
||||
srs_verbose("amf0 read empty string. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// data
|
||||
if (!stream->require(len)) {
|
||||
srs_warn("amf0 read string data failed");
|
||||
return str;
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 read string data failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
str = stream->read_string(len);
|
||||
std::string str = stream->read_string(len);
|
||||
|
||||
// support utf8-1 only
|
||||
// 1.3.1 Strings and UTF-8
|
||||
|
@ -80,54 +85,104 @@ std::string srs_amf0_read_utf8(SrsStream* stream)
|
|||
for (int i = 0; i < len; i++) {
|
||||
char ch = *(str.data() + i);
|
||||
if ((ch & 0x80) != 0) {
|
||||
srs_warn("only support utf8-1, 0x00-0x7F, actual is %#x", (int)ch);
|
||||
return "";
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("only support utf8-1, 0x00-0x7F, actual is %#x. ret=%d", (int)ch, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
value = str;
|
||||
srs_verbose("amf0 read string data success. str=%s", str.c_str());
|
||||
|
||||
return str;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string srs_amf0_read_string(SrsStream* stream)
|
||||
int srs_amf0_read_string(SrsStream* stream, std::string& value)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// marker
|
||||
if (!stream->require(1)) {
|
||||
srs_warn("amf0 read string marker failed");
|
||||
return "";
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 read string marker failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 "";
|
||||
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);
|
||||
return srs_amf0_read_utf8(stream, value);
|
||||
}
|
||||
|
||||
double srs_amf0_read_number(SrsStream* stream)
|
||||
int srs_amf0_read_boolean(SrsStream* stream, bool& value)
|
||||
{
|
||||
double value = 0;
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// marker
|
||||
if (!stream->require(1)) {
|
||||
srs_warn("amf0 read number marker failed");
|
||||
return value;
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 read bool marker failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char marker = stream->read_char();
|
||||
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_char() == 0) {
|
||||
value = false;
|
||||
} else {
|
||||
value = true;
|
||||
}
|
||||
|
||||
srs_verbose("amf0 read bool value success. value=%d", value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srs_amf0_read_number(SrsStream* stream, double& value)
|
||||
{
|
||||
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_char();
|
||||
if (marker != RTMP_AMF0_Number) {
|
||||
srs_warn("amf0 check number marker failed. marker=%#x, required=%#x", marker, RTMP_AMF0_Number);
|
||||
return value;
|
||||
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)) {
|
||||
srs_warn("amf0 read number value failed");
|
||||
return value;
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 read number value failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t temp = stream->read_8bytes();
|
||||
|
@ -135,13 +190,158 @@ double srs_amf0_read_number(SrsStream* stream)
|
|||
|
||||
srs_verbose("amf0 read number value success. value=%.2f", value);
|
||||
|
||||
return value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsAmf0Object* srs_amf0_read_object(SrsStream* stream)
|
||||
int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any*& value)
|
||||
{
|
||||
SrsAmf0Object* value = NULL;
|
||||
return value;
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// 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_char();
|
||||
srs_verbose("amf0 any marker success");
|
||||
|
||||
// backward the 1byte marker.
|
||||
stream->skip(-1);
|
||||
|
||||
switch (marker) {
|
||||
case RTMP_AMF0_String: {
|
||||
std::string data;
|
||||
if ((ret = srs_amf0_read_string(stream, data)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
value = new SrsAmf0String();
|
||||
srs_amf0_convert<SrsAmf0String>(value)->value = data;
|
||||
return ret;
|
||||
}
|
||||
case RTMP_AMF0_Boolean: {
|
||||
bool data;
|
||||
if ((ret = srs_amf0_read_boolean(stream, data)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
value = new SrsAmf0Boolean();
|
||||
srs_amf0_convert<SrsAmf0Boolean>(value)->value = data;
|
||||
return ret;
|
||||
}
|
||||
case RTMP_AMF0_Number: {
|
||||
double data;
|
||||
if ((ret = srs_amf0_read_number(stream, data)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
value = new SrsAmf0Number();
|
||||
srs_amf0_convert<SrsAmf0Number>(value)->value = data;
|
||||
return ret;
|
||||
}
|
||||
case RTMP_AMF0_ObjectEnd: {
|
||||
SrsAmf0ObjectEOF* p = NULL;
|
||||
if ((ret = srs_amf0_read_object_eof(stream, p)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
value = p;
|
||||
return ret;
|
||||
}
|
||||
case RTMP_AMF0_Object: {
|
||||
SrsAmf0Object* p = NULL;
|
||||
if ((ret = srs_amf0_read_object(stream, p)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
value = p;
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
value = new SrsAmf0Any();
|
||||
value->marker = stream->read_char();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*& value)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// 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_char();
|
||||
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");
|
||||
|
||||
// value
|
||||
value = new SrsAmf0ObjectEOF();
|
||||
srs_verbose("amf0 read object eof marker success");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value)
|
||||
{
|
||||
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_char();
|
||||
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
|
||||
value = new SrsAmf0Object();
|
||||
|
||||
while (!stream->empty()) {
|
||||
// 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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// AMF0 Object EOF.
|
||||
if (property_name.empty() || !property_value || property_value->is_object_eof()) {
|
||||
if (property_value) {
|
||||
delete property_value;
|
||||
}
|
||||
srs_info("amf0 read object EOF.");
|
||||
break;
|
||||
}
|
||||
|
||||
// add property
|
||||
value->properties[property_name] = property_value;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsAmf0Any::SrsAmf0Any()
|
||||
|
@ -158,6 +358,11 @@ bool SrsAmf0Any::is_string()
|
|||
return marker == RTMP_AMF0_String;
|
||||
}
|
||||
|
||||
bool SrsAmf0Any::is_boolean()
|
||||
{
|
||||
return marker == RTMP_AMF0_Boolean;
|
||||
}
|
||||
|
||||
bool SrsAmf0Any::is_number()
|
||||
{
|
||||
return marker == RTMP_AMF0_Number;
|
||||
|
@ -168,6 +373,11 @@ bool SrsAmf0Any::is_object()
|
|||
return marker == RTMP_AMF0_Object;
|
||||
}
|
||||
|
||||
bool SrsAmf0Any::is_object_eof()
|
||||
{
|
||||
return marker == RTMP_AMF0_ObjectEnd;
|
||||
}
|
||||
|
||||
SrsAmf0String::SrsAmf0String()
|
||||
{
|
||||
marker = RTMP_AMF0_String;
|
||||
|
@ -177,6 +387,16 @@ SrsAmf0String::~SrsAmf0String()
|
|||
{
|
||||
}
|
||||
|
||||
SrsAmf0Boolean::SrsAmf0Boolean()
|
||||
{
|
||||
marker = RTMP_AMF0_Boolean;
|
||||
value = false;
|
||||
}
|
||||
|
||||
SrsAmf0Boolean::~SrsAmf0Boolean()
|
||||
{
|
||||
}
|
||||
|
||||
SrsAmf0Number::SrsAmf0Number()
|
||||
{
|
||||
marker = RTMP_AMF0_Number;
|
||||
|
@ -185,12 +405,12 @@ SrsAmf0Number::SrsAmf0Number()
|
|||
|
||||
SrsAmf0Number::~SrsAmf0Number()
|
||||
{
|
||||
marker = RTMP_AMF0_ObjectEnd;
|
||||
}
|
||||
|
||||
SrsAmf0ObjectEOF::SrsAmf0ObjectEOF()
|
||||
{
|
||||
utf8_empty = 0x00;
|
||||
object_end_marker = RTMP_AMF0_ObjectEnd;
|
||||
}
|
||||
|
||||
SrsAmf0ObjectEOF::~SrsAmf0ObjectEOF()
|
||||
|
|
|
@ -43,25 +43,30 @@ class SrsAmf0Object;
|
|||
* 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);
|
||||
extern int srs_amf0_read_utf8(SrsStream* stream, std::string& value);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
extern int srs_amf0_read_string(SrsStream* stream, std::string& value);
|
||||
|
||||
/**
|
||||
* read amf0 boolean from stream.
|
||||
* 2.4 String Type
|
||||
* boolean-type = boolean-marker U8
|
||||
* 0 is false, <> 0 is true
|
||||
*/
|
||||
extern int srs_amf0_read_boolean(SrsStream* stream, bool& value);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
extern int srs_amf0_read_number(SrsStream* stream, double& value);
|
||||
|
||||
/**
|
||||
* read amf0 object from stream.
|
||||
|
@ -69,7 +74,7 @@ extern double srs_amf0_read_number(SrsStream* stream);
|
|||
* 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);
|
||||
extern int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value);
|
||||
|
||||
/**
|
||||
* any amf0 value.
|
||||
|
@ -87,22 +92,10 @@ struct SrsAmf0Any
|
|||
virtual ~SrsAmf0Any();
|
||||
|
||||
virtual bool is_string();
|
||||
virtual bool is_boolean();
|
||||
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<class T>
|
||||
T* convert()
|
||||
{
|
||||
T* p = dynamic_cast<T>(this);
|
||||
srs_assert(p != NULL);
|
||||
return p;
|
||||
}
|
||||
virtual bool is_object_eof();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -119,6 +112,21 @@ struct SrsAmf0String : public SrsAmf0Any
|
|||
virtual ~SrsAmf0String();
|
||||
};
|
||||
|
||||
/**
|
||||
* read amf0 boolean from stream.
|
||||
* 2.4 String Type
|
||||
* boolean-type = boolean-marker U8
|
||||
* 0 is false, <> 0 is true
|
||||
* @return default value is false.
|
||||
*/
|
||||
struct SrsAmf0Boolean : public SrsAmf0Any
|
||||
{
|
||||
bool value;
|
||||
|
||||
SrsAmf0Boolean();
|
||||
virtual ~SrsAmf0Boolean();
|
||||
};
|
||||
|
||||
/**
|
||||
* read amf0 number from stream.
|
||||
* 2.2 Number Type
|
||||
|
@ -138,10 +146,9 @@ struct SrsAmf0Number : public SrsAmf0Any
|
|||
* object-end-type = UTF-8-empty object-end-marker
|
||||
* 0x00 0x00 0x09
|
||||
*/
|
||||
struct SrsAmf0ObjectEOF
|
||||
struct SrsAmf0ObjectEOF : public SrsAmf0Any
|
||||
{
|
||||
int16_t utf8_empty;
|
||||
char object_end_marker;
|
||||
|
||||
SrsAmf0ObjectEOF();
|
||||
virtual ~SrsAmf0ObjectEOF();
|
||||
|
@ -160,5 +167,19 @@ struct SrsAmf0Object : public SrsAmf0Any
|
|||
SrsAmf0Object();
|
||||
virtual ~SrsAmf0Object();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<class T>
|
||||
T* srs_amf0_convert(SrsAmf0Any* any)
|
||||
{
|
||||
T* p = dynamic_cast<T*>(any);
|
||||
srs_assert(p != NULL);
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -281,7 +281,11 @@ int SrsMessage::decode_packet()
|
|||
}
|
||||
srs_verbose("decode stream initialized success");
|
||||
|
||||
std::string command = srs_amf0_read_string(stream);
|
||||
std::string command;
|
||||
if ((ret = srs_amf0_read_string(stream, command)) != ERROR_SUCCESS) {
|
||||
srs_error("decode AMF0 command name failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_verbose("AMF0 command message, command_name=%s", command.c_str());
|
||||
|
||||
stream->reset();
|
||||
|
@ -337,7 +341,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
command_name = srs_amf0_read_string(stream);
|
||||
if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) {
|
||||
srs_error("amf0 decode connect command_name failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (command_name.empty() || command_name != RTMP_AMF0_COMMAND_CONNECT) {
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 decode connect command_name failed. "
|
||||
|
@ -345,7 +352,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
transaction_id = srs_amf0_read_number(stream);
|
||||
if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) {
|
||||
srs_error("amf0 decode connect transaction_id failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (transaction_id != 1.0) {
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 decode connect transaction_id failed. "
|
||||
|
@ -353,7 +363,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
command_object = srs_amf0_read_object(stream);
|
||||
if ((ret = srs_amf0_read_object(stream, command_object)) != ERROR_SUCCESS) {
|
||||
srs_error("amf0 decode connect command_object failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (command_object == NULL) {
|
||||
ret = ERROR_RTMP_AMF0_DECODE;
|
||||
srs_error("amf0 decode connect command_object failed. ret=%d", ret);
|
||||
|
|
|
@ -238,6 +238,7 @@ public:
|
|||
|
||||
*pmsg = msg;
|
||||
*ppacket = pkt;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -70,7 +70,12 @@ bool SrsStream::empty()
|
|||
|
||||
bool SrsStream::require(int required_size)
|
||||
{
|
||||
return !empty() && (required_size < bytes + size - p);
|
||||
return !empty() && (required_size <= bytes + size - p);
|
||||
}
|
||||
|
||||
void SrsStream::skip(int size)
|
||||
{
|
||||
p += size;
|
||||
}
|
||||
|
||||
char SrsStream::read_char()
|
||||
|
|
|
@ -65,6 +65,11 @@ public:
|
|||
* @return true if stream can read/write specified required_size bytes.
|
||||
*/
|
||||
virtual bool require(int required_size);
|
||||
/**
|
||||
* to skip some size.
|
||||
* @size can be any value. positive to forward; nagetive to backward.
|
||||
*/
|
||||
virtual void skip(int size);
|
||||
public:
|
||||
/**
|
||||
* get 1bytes char from stream.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue