winlin

fix RTMP protocol extended timestamp bug, always trust and use the extended-time…

…stamp for the first chunk of msg
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "86" 34 +#define VERSION_REVISION "87"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "srs" 37 #define RTMP_SIG_SRS_KEY "srs"
@@ -301,7 +301,6 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io) @@ -301,7 +301,6 @@ SrsProtocol::SrsProtocol(ISrsProtocolReaderWriter* io)
301 skt = io; 301 skt = io;
302 302
303 in_chunk_size = out_chunk_size = RTMP_DEFAULT_CHUNK_SIZE; 303 in_chunk_size = out_chunk_size = RTMP_DEFAULT_CHUNK_SIZE;
304 - send_extended_timestamp_for_C3_chunk = true;  
305 } 304 }
306 305
307 SrsProtocol::~SrsProtocol() 306 SrsProtocol::~SrsProtocol()
@@ -405,7 +404,7 @@ int SrsProtocol::recv_message(SrsMessage** pmsg) @@ -405,7 +404,7 @@ int SrsProtocol::recv_message(SrsMessage** pmsg)
405 return ret; 404 return ret;
406 } 405 }
407 406
408 - srs_verbose("got a msg, cid=%d, type=%d, size=%d, time=%"PRId64, 407 + srs_warn("got a msg, cid=%d, type=%d, size=%d, time=%"PRId64,
409 msg->header.perfer_cid, msg->header.message_type, msg->header.payload_length, 408 msg->header.perfer_cid, msg->header.message_type, msg->header.payload_length,
410 msg->header.timestamp); 409 msg->header.timestamp);
411 *pmsg = msg; 410 *pmsg = msg;
@@ -527,7 +526,7 @@ int SrsProtocol::do_send_and_free_message(SrsMessage* msg, SrsPacket* packet) @@ -527,7 +526,7 @@ int SrsProtocol::do_send_and_free_message(SrsMessage* msg, SrsPacket* packet)
527 // @see: ngx_rtmp_prepare_message 526 // @see: ngx_rtmp_prepare_message
528 // @see: http://blog.csdn.net/win_lin/article/details/13363699 527 // @see: http://blog.csdn.net/win_lin/article/details/13363699
529 u_int32_t timestamp = (u_int32_t)msg->header.timestamp; 528 u_int32_t timestamp = (u_int32_t)msg->header.timestamp;
530 - if(send_extended_timestamp_for_C3_chunk && timestamp >= RTMP_EXTENDED_TIMESTAMP){ 529 + if(timestamp >= RTMP_EXTENDED_TIMESTAMP){
531 pp = (char*)&timestamp; 530 pp = (char*)&timestamp;
532 *pheader++ = pp[3]; 531 *pheader++ = pp[3];
533 *pheader++ = pp[2]; 532 *pheader++ = pp[2];
@@ -958,8 +957,8 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -958,8 +957,8 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
958 // the fmt must be 0, a new stream. 957 // the fmt must be 0, a new stream.
959 if (chunk->msg_count == 0 && fmt != RTMP_FMT_TYPE0) { 958 if (chunk->msg_count == 0 && fmt != RTMP_FMT_TYPE0) {
960 ret = ERROR_RTMP_CHUNK_START; 959 ret = ERROR_RTMP_CHUNK_START;
961 - srs_error("chunk stream is fresh, "  
962 - "fmt must be %d, actual is %d. ret=%d", RTMP_FMT_TYPE0, fmt, ret); 960 + srs_error("chunk stream is fresh, fmt must be %d, actual is %d. cid=%d, ret=%d",
  961 + RTMP_FMT_TYPE0, fmt, chunk->cid, ret);
963 return ret; 962 return ret;
964 } 963 }
965 964
@@ -973,7 +972,9 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -973,7 +972,9 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
973 } 972 }
974 973
975 // create msg when new chunk stream start 974 // create msg when new chunk stream start
  975 + bool is_first_chunk_of_msg = false;
976 if (!chunk->msg) { 976 if (!chunk->msg) {
  977 + is_first_chunk_of_msg = true;
977 chunk->msg = new SrsMessage(); 978 chunk->msg = new SrsMessage();
978 srs_verbose("create message for new chunk, fmt=%d, cid=%d", fmt, chunk->cid); 979 srs_verbose("create message for new chunk, fmt=%d, cid=%d", fmt, chunk->cid);
979 } 980 }
@@ -992,7 +993,13 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -992,7 +993,13 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
992 } 993 }
993 char* p = buffer->bytes() + bh_size; 994 char* p = buffer->bytes() + bh_size;
994 995
995 - // parse the message header. 996 + /**
  997 + * parse the message header.
  998 + * 3bytes: timestamp delta, fmt=0,1,2
  999 + * 3bytes: payload length, fmt=0,1
  1000 + * 1bytes: message type, fmt=0,1
  1001 + * 4bytes: stream id, fmt=0
  1002 + */
996 // see also: ngx_rtmp_recv 1003 // see also: ngx_rtmp_recv
997 if (fmt <= RTMP_FMT_TYPE2) { 1004 if (fmt <= RTMP_FMT_TYPE2) {
998 char* pp = (char*)&chunk->header.timestamp_delta; 1005 char* pp = (char*)&chunk->header.timestamp_delta;
@@ -1015,7 +1022,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -1015,7 +1022,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
1015 // timestamp header’ MUST be present. Otherwise, this value SHOULD be 1022 // timestamp header’ MUST be present. Otherwise, this value SHOULD be
1016 // the entire delta. 1023 // the entire delta.
1017 chunk->extended_timestamp = (chunk->header.timestamp_delta >= RTMP_EXTENDED_TIMESTAMP); 1024 chunk->extended_timestamp = (chunk->header.timestamp_delta >= RTMP_EXTENDED_TIMESTAMP);
1018 - if (chunk->extended_timestamp) { 1025 + if (!chunk->extended_timestamp) {
1019 // Extended timestamp: 0 or 4 bytes 1026 // Extended timestamp: 0 or 4 bytes
1020 // This field MUST be sent when the normal timsestamp is set to 1027 // This field MUST be sent when the normal timsestamp is set to
1021 // 0xffffff, it MUST NOT be sent if the normal timestamp is set to 1028 // 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 @@ -1024,12 +1031,6 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
1024 // MUST NOT be present. For values greater than or equal to 0xffffff 1031 // MUST NOT be present. For values greater than or equal to 0xffffff
1025 // the normal timestamp field MUST NOT be used and MUST be set to 1032 // the normal timestamp field MUST NOT be used and MUST be set to
1026 // 0xffffff and the extended timestamp MUST be sent. 1033 // 0xffffff and the extended timestamp MUST be sent.
1027 - //  
1028 - // if extended timestamp, the timestamp must >= RTMP_EXTENDED_TIMESTAMP  
1029 - // we set the timestamp to RTMP_EXTENDED_TIMESTAMP to identify we  
1030 - // got an extended timestamp.  
1031 - chunk->header.timestamp = RTMP_EXTENDED_TIMESTAMP;  
1032 - } else {  
1033 if (fmt == RTMP_FMT_TYPE0) { 1034 if (fmt == RTMP_FMT_TYPE0) {
1034 // 6.1.2.1. Type 0 1035 // 6.1.2.1. Type 0
1035 // For a type-0 chunk, the absolute timestamp of the message is sent 1036 // 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 @@ -1090,7 +1091,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
1090 } 1091 }
1091 1092
1092 // read extended-timestamp 1093 // read extended-timestamp
1093 - if (chunk->extended_timestamp && send_extended_timestamp_for_C3_chunk) { 1094 + if (chunk->extended_timestamp) {
1094 mh_size += 4; 1095 mh_size += 4;
1095 required_size = bh_size + mh_size; 1096 required_size = bh_size + mh_size;
1096 srs_verbose("read header ext time. fmt=%d, ext_time=%d, mh_size=%d", fmt, chunk->extended_timestamp, mh_size); 1097 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 @@ -1108,14 +1109,35 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
1108 pp[1] = *p++; 1109 pp[1] = *p++;
1109 pp[0] = *p++; 1110 pp[0] = *p++;
1110 1111
1111 - // ffmpeg/librtmp may donot send this filed, need to detect the value.  
1112 - // @see also: http://blog.csdn.net/win_lin/article/details/13363699  
1113 - // compare to the chunk timestamp, which is set by chunk message header  
1114 - // type 0,1 or 2. 1112 + /**
  1113 + * RTMP specification and ffmpeg/librtmp is false,
  1114 + * but, adobe changed the specification, so flash/FMLE/FMS always true.
  1115 + * default to true to support flash/FMLE/FMS.
  1116 + *
  1117 + * ffmpeg/librtmp may donot send this filed, need to detect the value.
  1118 + * @see also: http://blog.csdn.net/win_lin/article/details/13363699
  1119 + * compare to the chunk timestamp, which is set by chunk message header
  1120 + * type 0,1 or 2.
  1121 + *
  1122 + * @remark, nginx send the extended-timestamp in sequence-header,
  1123 + * and timestamp delta in continue C1 chunks, and so compatible with ffmpeg,
  1124 + * that is, there is no continue chunks and extended-timestamp in nginx-rtmp.
  1125 + *
  1126 + * @remark, srs always send the extended-timestamp, to keep simple,
  1127 + * and compatible with adobe products.
  1128 + */
1115 u_int32_t chunk_timestamp = chunk->header.timestamp; 1129 u_int32_t chunk_timestamp = chunk->header.timestamp;
1116 - if (chunk_timestamp > RTMP_EXTENDED_TIMESTAMP && chunk_timestamp != timestamp) { 1130 +
  1131 + /**
  1132 + * if chunk_timestamp<=0, the chunk previous packet has no extended-timestamp,
  1133 + * always use the extended timestamp.
  1134 + */
  1135 + /**
  1136 + * about the is_first_chunk_of_msg.
  1137 + * @remark, for the first chunk of message, always use the extended timestamp.
  1138 + */
  1139 + if (!is_first_chunk_of_msg && chunk_timestamp > 0 && chunk_timestamp != timestamp) {
1117 mh_size -= 4; 1140 mh_size -= 4;
1118 - send_extended_timestamp_for_C3_chunk = false;  
1119 srs_warn("no 4bytes extended timestamp in the continued chunk"); 1141 srs_warn("no 4bytes extended timestamp in the continued chunk");
1120 } else { 1142 } else {
1121 chunk->header.timestamp = timestamp; 1143 chunk->header.timestamp = timestamp;
@@ -107,24 +107,6 @@ private: @@ -107,24 +107,6 @@ private:
107 * value: the request command name 107 * value: the request command name
108 */ 108 */
109 std::map<double, std::string> requests; 109 std::map<double, std::string> requests;
110 - /**  
111 - * RTMP specification and ffmpeg/librtmp is false,  
112 - * but, adobe changed the specification, so flash/FMLE/FMS always true.  
113 - * default to true to support flash/FMLE/FMS.  
114 - *  
115 - * ffmpeg/librtmp may donot send this filed, need to detect the value.  
116 - * @see also: http://blog.csdn.net/win_lin/article/details/13363699  
117 - * compare to the chunk timestamp, which is set by chunk message header  
118 - * type 0,1 or 2.  
119 - *  
120 - * @remark, nginx send the extended-timestamp in sequence-header,  
121 - * and timestamp delta in continue C1 chunks, and so compatible with ffmpeg,  
122 - * that is, there is no continue chunks and extended-timestamp in nginx-rtmp.  
123 - *  
124 - * @remark, srs always send the extended-timestamp, to keep simple,  
125 - * and compatible with adobe products.  
126 - */  
127 - bool send_extended_timestamp_for_C3_chunk;  
128 // peer in 110 // peer in
129 private: 111 private:
130 std::map<int, SrsChunkStream*> chunk_streams; 112 std::map<int, SrsChunkStream*> chunk_streams;