From dee3f6522810a55e71352bbab2361349b84098a2 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Sun, 21 Aug 2011 18:45:59 +0200 Subject: [PATCH] Some RTMP timestamp issues found and fixed, as well as some RTMP Parser fixes (but now segfaults? Needs more testing...) --- Connector_RTMP/main.cpp | 8 ++++---- RTMP_Parser/main.cpp | 18 +++++++++--------- util/rtmpchunks.cpp | 14 ++++++++------ util/rtmpchunks.h | 1 + 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Connector_RTMP/main.cpp b/Connector_RTMP/main.cpp index 7ad9a403..e07b7d29 100644 --- a/Connector_RTMP/main.cpp +++ b/Connector_RTMP/main.cpp @@ -372,7 +372,7 @@ void Connector_RTMP::parseChunk(){ if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);} } streamname = "/tmp/shared_socket_" + streamname; - //Socket.write(RTMPStream::SendUSR(0, 1));//send UCM StreamBegin (0), stream 1 + Socket.write(RTMPStream::SendUSR(0, 1));//send UCM StreamBegin (0), stream 1 //send a status reply AMF::Object amfreply("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("", "onStatus"));//status reply @@ -383,7 +383,7 @@ void Connector_RTMP::parseChunk(){ amfreply.getContentP(3)->addContent(AMF::Object("code", "NetStream.Play.Reset")); amfreply.getContentP(3)->addContent(AMF::Object("description", "Playing and resetting...")); amfreply.getContentP(3)->addContent(AMF::Object("details", "PLS")); - amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1)); + amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); #if DEBUG >= 4 amfreply.Print(); #endif @@ -397,7 +397,7 @@ void Connector_RTMP::parseChunk(){ amfreply.getContentP(3)->addContent(AMF::Object("code", "NetStream.Play.Start")); amfreply.getContentP(3)->addContent(AMF::Object("description", "Playing!")); amfreply.getContentP(3)->addContent(AMF::Object("details", "PLS")); - amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1)); + amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); #if DEBUG >= 4 amfreply.Print(); #endif @@ -528,7 +528,7 @@ void Connector_RTMP::parseChunk(){ if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);} } streamname = "/tmp/shared_socket_" + streamname; - //Socket.write(RTMPStream::SendUSR(0, 1));//send UCM StreamBegin (0), stream 1 + Socket.write(RTMPStream::SendUSR(0, 1));//send UCM StreamBegin (0), stream 1 //send a status reply AMF::Object amfreply("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("", "onStatus"));//status reply diff --git a/RTMP_Parser/main.cpp b/RTMP_Parser/main.cpp index 09debfb0..9ab21b35 100644 --- a/RTMP_Parser/main.cpp +++ b/RTMP_Parser/main.cpp @@ -55,7 +55,7 @@ int main(int argc, char ** argv){ while (next.Parse(inbuffer)){ if ((Detail & DETAIL_VERBOSE) == DETAIL_VERBOSE){ - fprintf(stderr, "Chunk info: CS ID %u, timestamp %u, len %u, type ID %u, Stream ID %u\n", next.cs_id, next.timestamp, next.len, next.msg_type_id, next.msg_stream_id); + fprintf(stderr, "Chunk info: [%#2X] CS ID %u, timestamp %u, len %u, type ID %u, Stream ID %u\n", next.headertype, next.cs_id, next.timestamp, next.len, next.msg_type_id, next.msg_stream_id); } switch (next.msg_type_id){ case 0://does not exist @@ -78,28 +78,28 @@ int main(int argc, char ** argv){ short int ucmtype = ntohs(*(short int*)next.data.c_str()); switch (ucmtype){ case 0: - fprintf(stderr, "CTRL: User control message: stream begin %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: stream begin %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; case 1: - fprintf(stderr, "CTRL: User control message: stream EOF %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: stream EOF %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; case 2: - fprintf(stderr, "CTRL: User control message: stream dry %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: stream dry %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; case 3: - fprintf(stderr, "CTRL: User control message: setbufferlen %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: setbufferlen %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; case 4: - fprintf(stderr, "CTRL: User control message: streamisrecorded %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: streamisrecorded %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; case 6: - fprintf(stderr, "CTRL: User control message: pingrequest %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: pingrequest %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; case 7: - fprintf(stderr, "CTRL: User control message: pingresponse %i\n", ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: pingresponse %u\n", ntohl(*(unsigned int*)(next.data.c_str()+2))); break; default: - fprintf(stderr, "CTRL: User control message: UNKNOWN %hi - %i\n", ucmtype, ntohl(*(int*)next.data.c_str()+2)); + fprintf(stderr, "CTRL: User control message: UNKNOWN %hu - %u\n", ucmtype, ntohl(*(unsigned int*)(next.data.c_str()+2))); break; } } break; diff --git a/util/rtmpchunks.cpp b/util/rtmpchunks.cpp index 574bcf53..f6f11076 100644 --- a/util/rtmpchunks.cpp +++ b/util/rtmpchunks.cpp @@ -42,6 +42,7 @@ std::string RTMPStream::Chunk::Pack(){ unsigned int tmpi; unsigned char chtype = 0x00; timestamp -= firsttime; + if (timestamp < prev.timestamp){timestamp = prev.timestamp;} if ((prev.msg_type_id > 0) && (prev.cs_id == cs_id)){ if (msg_stream_id == prev.msg_stream_id){ chtype = 0x40;//do not send msg_stream_id @@ -215,7 +216,7 @@ std::string RTMPStream::SendUSR(unsigned char type, unsigned int data){ ch.msg_type_id = 4; ch.msg_stream_id = 0; ch.data.resize(6); - *(unsigned int*)((char*)ch.data.c_str()+2) = htonl(data); + *(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data); ch.data[0] = 0; ch.data[1] = type; return ch.Pack(); @@ -232,8 +233,8 @@ std::string RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned ch.msg_type_id = 4; ch.msg_stream_id = 0; ch.data.resize(10); - *(unsigned int*)((char*)ch.data.c_str()+2) = htonl(data); - *(unsigned int*)((char*)ch.data.c_str()+6) = htonl(data2); + *(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data); + *(unsigned int*)(((char*)ch.data.c_str())+6) = htonl(data2); ch.data[0] = 0; ch.data[1] = type; return ch.Pack(); @@ -274,7 +275,8 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ RTMPStream::Chunk prev = lastrecv[cs_id]; //process the rest of the header, for each chunk type - switch (chunktype & 0xC0){ + headertype = chunktype & 0xC0; + switch (headertype){ case 0x00: if (indata.size() < i+11) return false; //can't read whole header timestamp = indata[i++]*256*256; @@ -296,7 +298,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ timestamp = indata[i++]*256*256; timestamp += indata[i++]*256; timestamp += indata[i++]; - timestamp += prev.timestamp; + if (timestamp != 0x00ffffff){timestamp += prev.timestamp;} len = indata[i++]*256*256; len += indata[i++]*256; len += indata[i++]; @@ -310,7 +312,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){ timestamp = indata[i++]*256*256; timestamp += indata[i++]*256; timestamp += indata[i++]; - timestamp += prev.timestamp; + if (timestamp != 0x00ffffff){timestamp += prev.timestamp;} len = prev.len; len_left = prev.len_left; msg_type_id = prev.msg_type_id; diff --git a/util/rtmpchunks.h b/util/rtmpchunks.h index 8feeefb0..b114f440 100644 --- a/util/rtmpchunks.h +++ b/util/rtmpchunks.h @@ -30,6 +30,7 @@ namespace RTMPStream{ /// Holds a single RTMP chunk, either send or receive direction. class Chunk{ public: + unsigned char headertype; ///< For input chunks, the type of header. This is calculated automatically for output chunks. unsigned int cs_id; ///< ContentStream ID unsigned int timestamp; ///< Timestamp of this chunk. unsigned int len; ///< Length of the complete chunk.