From 0945c2b441881cb048e9440c69e8495e3d6aebe1 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 30 Apr 2014 17:16:28 +0800 Subject: [PATCH] fix RTMP protocol extended timestamp bug, always trust and use the extended-timestamp for the first chunk of msg --- trunk/src/core/srs_core.hpp | 2 +- trunk/src/rtmp/srs_protocol_rtmp_stack.cpp | 62 +++++++++++++++------- trunk/src/rtmp/srs_protocol_rtmp_stack.hpp | 18 ------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index daa9e9a24..426372db5 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "86" +#define VERSION_REVISION "87" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "srs" diff --git a/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp b/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp index 8ce9931f9..949eee877 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp +++ b/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp @@ -301,7 +301,6 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io) skt = io; in_chunk_size = out_chunk_size = RTMP_DEFAULT_CHUNK_SIZE; - send_extended_timestamp_for_C3_chunk = true; } SrsProtocol::~SrsProtocol() @@ -405,7 +404,7 @@ int SrsProtocol::recv_message(SrsMessage** pmsg) return ret; } - srs_verbose("got a msg, cid=%d, type=%d, size=%d, time=%"PRId64, + srs_warn("got a msg, cid=%d, type=%d, size=%d, time=%"PRId64, msg->header.perfer_cid, msg->header.message_type, msg->header.payload_length, msg->header.timestamp); *pmsg = msg; @@ -527,7 +526,7 @@ int SrsProtocol::do_send_and_free_message(SrsMessage* msg, SrsPacket* packet) // @see: ngx_rtmp_prepare_message // @see: http://blog.csdn.net/win_lin/article/details/13363699 u_int32_t timestamp = (u_int32_t)msg->header.timestamp; - if(send_extended_timestamp_for_C3_chunk && timestamp >= RTMP_EXTENDED_TIMESTAMP){ + if(timestamp >= RTMP_EXTENDED_TIMESTAMP){ pp = (char*)×tamp; *pheader++ = pp[3]; *pheader++ = pp[2]; @@ -958,8 +957,8 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz // the fmt must be 0, a new stream. if (chunk->msg_count == 0 && fmt != RTMP_FMT_TYPE0) { ret = ERROR_RTMP_CHUNK_START; - srs_error("chunk stream is fresh, " - "fmt must be %d, actual is %d. ret=%d", RTMP_FMT_TYPE0, fmt, ret); + srs_error("chunk stream is fresh, fmt must be %d, actual is %d. cid=%d, ret=%d", + RTMP_FMT_TYPE0, fmt, chunk->cid, ret); return ret; } @@ -973,7 +972,9 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz } // create msg when new chunk stream start + bool is_first_chunk_of_msg = false; if (!chunk->msg) { + is_first_chunk_of_msg = true; chunk->msg = new SrsMessage(); srs_verbose("create message for new chunk, fmt=%d, cid=%d", fmt, chunk->cid); } @@ -992,7 +993,13 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz } char* p = buffer->bytes() + bh_size; - // parse the message header. + /** + * parse the message header. + * 3bytes: timestamp delta, fmt=0,1,2 + * 3bytes: payload length, fmt=0,1 + * 1bytes: message type, fmt=0,1 + * 4bytes: stream id, fmt=0 + */ // see also: ngx_rtmp_recv if (fmt <= RTMP_FMT_TYPE2) { char* pp = (char*)&chunk->header.timestamp_delta; @@ -1015,7 +1022,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz // timestamp header’ MUST be present. Otherwise, this value SHOULD be // the entire delta. chunk->extended_timestamp = (chunk->header.timestamp_delta >= RTMP_EXTENDED_TIMESTAMP); - if (chunk->extended_timestamp) { + if (!chunk->extended_timestamp) { // Extended timestamp: 0 or 4 bytes // This field MUST be sent when the normal timsestamp is set to // 0xffffff, it MUST NOT be sent if the normal timestamp is set to @@ -1024,12 +1031,6 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz // MUST NOT be present. For values greater than or equal to 0xffffff // the normal timestamp field MUST NOT be used and MUST be set to // 0xffffff and the extended timestamp MUST be sent. - // - // if extended timestamp, the timestamp must >= RTMP_EXTENDED_TIMESTAMP - // we set the timestamp to RTMP_EXTENDED_TIMESTAMP to identify we - // got an extended timestamp. - chunk->header.timestamp = RTMP_EXTENDED_TIMESTAMP; - } else { if (fmt == RTMP_FMT_TYPE0) { // 6.1.2.1. Type 0 // For a type-0 chunk, the absolute timestamp of the message is sent @@ -1090,7 +1091,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz } // read extended-timestamp - if (chunk->extended_timestamp && send_extended_timestamp_for_C3_chunk) { + if (chunk->extended_timestamp) { mh_size += 4; required_size = bh_size + mh_size; srs_verbose("read header ext time. fmt=%d, ext_time=%d, mh_size=%d", fmt, chunk->extended_timestamp, mh_size); @@ -1108,14 +1109,35 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz pp[1] = *p++; pp[0] = *p++; - // ffmpeg/librtmp may donot send this filed, need to detect the value. - // @see also: http://blog.csdn.net/win_lin/article/details/13363699 - // compare to the chunk timestamp, which is set by chunk message header - // type 0,1 or 2. + /** + * RTMP specification and ffmpeg/librtmp is false, + * but, adobe changed the specification, so flash/FMLE/FMS always true. + * default to true to support flash/FMLE/FMS. + * + * ffmpeg/librtmp may donot send this filed, need to detect the value. + * @see also: http://blog.csdn.net/win_lin/article/details/13363699 + * compare to the chunk timestamp, which is set by chunk message header + * type 0,1 or 2. + * + * @remark, nginx send the extended-timestamp in sequence-header, + * and timestamp delta in continue C1 chunks, and so compatible with ffmpeg, + * that is, there is no continue chunks and extended-timestamp in nginx-rtmp. + * + * @remark, srs always send the extended-timestamp, to keep simple, + * and compatible with adobe products. + */ u_int32_t chunk_timestamp = chunk->header.timestamp; - if (chunk_timestamp > RTMP_EXTENDED_TIMESTAMP && chunk_timestamp != timestamp) { + + /** + * if chunk_timestamp<=0, the chunk previous packet has no extended-timestamp, + * always use the extended timestamp. + */ + /** + * about the is_first_chunk_of_msg. + * @remark, for the first chunk of message, always use the extended timestamp. + */ + if (!is_first_chunk_of_msg && chunk_timestamp > 0 && chunk_timestamp != timestamp) { mh_size -= 4; - send_extended_timestamp_for_C3_chunk = false; srs_warn("no 4bytes extended timestamp in the continued chunk"); } else { chunk->header.timestamp = timestamp; diff --git a/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp b/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp index a36edf47c..4f7e711b9 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp +++ b/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp @@ -107,24 +107,6 @@ private: * value: the request command name */ std::map requests; - /** - * RTMP specification and ffmpeg/librtmp is false, - * but, adobe changed the specification, so flash/FMLE/FMS always true. - * default to true to support flash/FMLE/FMS. - * - * ffmpeg/librtmp may donot send this filed, need to detect the value. - * @see also: http://blog.csdn.net/win_lin/article/details/13363699 - * compare to the chunk timestamp, which is set by chunk message header - * type 0,1 or 2. - * - * @remark, nginx send the extended-timestamp in sequence-header, - * and timestamp delta in continue C1 chunks, and so compatible with ffmpeg, - * that is, there is no continue chunks and extended-timestamp in nginx-rtmp. - * - * @remark, srs always send the extended-timestamp, to keep simple, - * and compatible with adobe products. - */ - bool send_extended_timestamp_for_C3_chunk; // peer in private: std::map chunk_streams;