RTMP: Use extended timestamp as delta when chunk fmt=1/2. v6.0.167 v7.0.37 (#4356)

1. When the chunk message header employs type 1 and type 2, the extended
timestamp denotes the time delta.
2. When the DTS (Decoding Time Stamp) experiences a jump and exceeds
16777215, there can be errors in DTS calculation, and if the audio and
video delta differs, it may result in audio-video synchronization
issues.

---------

`TRANS_BY_GPT4`

---------

Co-authored-by: 彭治湘 <zuolengchan@douyu.tv>
Co-authored-by: Haibo Chen(陈海博) <495810242@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: winlin <winlinvip@gmail.com>
This commit is contained in:
pengzhixiang 2025-05-30 02:20:22 +08:00 committed by winlin
parent 33b0a0fe7d
commit 9b942fafcc
6 changed files with 391 additions and 11 deletions

View File

@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a>
## SRS 7.0 Changelog
* v7.0, 2025-05-29, Merge [#4356](https://github.com/ossrs/srs/pull/4356): RTMP: Use extended timestamp as delta when chunk fmt=1/2. v7.0.37 (#4356)
* v7.0, 2025-05-29, Merge [#4363](https://github.com/ossrs/srs/pull/4363): Fix error about TestRtcPublish_HttpFlvPlay. v7.0.36 (#4363)
* v7.0, 2025-05-29, Merge [#4362](https://github.com/ossrs/srs/pull/4362): Update VSCode launch configuration to support GDB on Linux and LLDB on macOS. v7.0.35 (#4362)
* v7.0, 2025-05-26, Merge [#4359](https://github.com/ossrs/srs/pull/4359): update pion/webrtc to v4. v7.0.34 (#4359)
@ -47,6 +48,7 @@ The changelog for SRS.
<a name="v6-changes"></a>
## SRS 6.0 Changelog
* v6.0, 2025-05-29, Merge [#4356](https://github.com/ossrs/srs/pull/4356): RTMP: Use extended timestamp as delta when chunk fmt=1/2. v6.0.167 (#4356)
* v6.0, 2025-03-21, Merge [#4303](https://github.com/ossrs/srs/pull/4303): replace values with enums. v6.0.165 (#4303)
* v6.0, 2025-03-20, Merge [#4305](https://github.com/ossrs/srs/pull/4305): free sample to prevent memory leak. v6.0.164 (#4305)
* v6.0, 2025-03-18, Merge [#4302](https://github.com/ossrs/srs/pull/4302): update geekyeggo/delete-artifact to 5.0.0. v6.0.163 (#4302)

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 6
#define VERSION_MINOR 0
#define VERSION_REVISION 166
#define VERSION_REVISION 167
#endif

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 7
#define VERSION_MINOR 0
#define VERSION_REVISION 36
#define VERSION_REVISION 37
#endif

View File

@ -1032,8 +1032,8 @@ srs_error_t SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt)
// 0x00ffffff), this value MUST be 16777215, and the 'extended
// 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) {
chunk->has_extended_timestamp = (chunk->header.timestamp_delta >= RTMP_EXTENDED_TIMESTAMP);
if (!chunk->has_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
@ -1085,13 +1085,13 @@ srs_error_t SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt)
}
} else {
// update the timestamp even fmt=3 for first chunk packet
if (is_first_chunk_of_msg && !chunk->extended_timestamp) {
if (is_first_chunk_of_msg && !chunk->has_extended_timestamp) {
chunk->header.timestamp += chunk->header.timestamp_delta;
}
}
// read extended-timestamp
if (chunk->extended_timestamp) {
if (chunk->has_extended_timestamp) {
mh_size += 4;
if ((err = in_buffer->grow(skt, 4)) != srs_success) {
return srs_error_wrap(err, "read 4 bytes ext timestamp");
@ -1127,7 +1127,7 @@ srs_error_t SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt)
* @remark, srs always send the extended-timestamp, to keep simple,
* and compatible with adobe products.
*/
uint32_t chunk_timestamp = (uint32_t)chunk->header.timestamp;
uint32_t chunk_extended_timestamp = (uint32_t)chunk->extended_timestamp;
/**
* if chunk_timestamp<=0, the chunk previous packet has no extended-timestamp,
@ -1137,11 +1137,16 @@ srs_error_t SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt)
* 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) {
if (!is_first_chunk_of_msg && chunk_extended_timestamp > 0 && chunk_extended_timestamp != timestamp) {
mh_size -= 4;
in_buffer->skip(-4);
} else {
chunk->header.timestamp = timestamp;
chunk->extended_timestamp = timestamp;
if (fmt == RTMP_FMT_TYPE0) {
chunk->header.timestamp = timestamp;
} else if (is_first_chunk_of_msg) {
chunk->header.timestamp += timestamp;
}
}
}
@ -1439,9 +1444,10 @@ SrsChunkStream::SrsChunkStream(int _cid)
{
fmt = 0;
cid = _cid;
extended_timestamp = false;
has_extended_timestamp = false;
msg = NULL;
msg_count = 0;
extended_timestamp = 0;
}
SrsChunkStream::~SrsChunkStream()

View File

@ -380,11 +380,16 @@ public:
// Cached message header
SrsMessageHeader header;
// Whether the chunk message header has extended timestamp.
bool extended_timestamp;
bool has_extended_timestamp;
// The partially read message.
SrsCommonMessage* msg;
// Decoded msg count, to identify whether the chunk stream is fresh.
int64_t msg_count;
// Because the extended timestamp may be a delta timestamp, it can differ
// from the timestamp in the header, so it should be stored as a distinct field
// for comparison with the extended timestamp of subsequent chunks.
// See https://github.com/ossrs/srs/pull/4356 for details.
int32_t extended_timestamp;
public:
SrsChunkStream(int _cid);
virtual ~SrsChunkStream();

View File

@ -1199,6 +1199,373 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVExtTime2Trunk2)
EXPECT_EQ(0x00010203, msg->header.timestamp);
}
/**
* 2 audio and video packet, fmt 1/2
* first audio packet: dts:10000
* first video packet: dts:11000
* second audio packet: dts : 16787216 delta: 16777216
* second video packet: dts : 16787216 delta: 16776216
*/
VOID TEST(ProtocolStackTest, ProtocolRecvAVExtTimedeltaStream)
{
srs_error_t err = srs_success;
MockBufferIO bio;
SrsProtocol proto(&bio);
// audio message
uint8_t audio_data1[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x03, // fmt 0
0x00, 0x27, 0x10, // timestamp 10000
0x00, 0x00, 0x80, // length, 128
0x08, // message_type
0x00, 0x00, 0x00, 0x00, // stream_id
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
uint8_t audio_data2[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x43, // fmt 1
0xff, 0xff, 0xff, // means extended timestamp
0x00, 0x00, 0x80, // length, 128
0x08, // message_type
0x01, 0x00, 0x00, 0x00, // extended timestamp delta:16777216
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
// video message
uint8_t video_data1[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x04, // fmt 0
0x00, 0x2a, 0xf8, // timestamp 11000
0x00, 0x00, 0x80, // length, 128
0x09, // message_type
0x00, 0x00, 0x00, 0x01, // stream_id
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
uint8_t video_data2[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x44, // fmt 1
0xff, 0xff, 0xff, // means extended timestamp
0x00, 0x00, 0x80, // length, 128
0x09, // message_type
0x00, 0xff, 0xfc, 0x18, // extended timestamp delta:16776216
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
if (true) {
bio.in_buffer.append((char*)audio_data1, sizeof(audio_data1));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_audio());
EXPECT_EQ(0x00002710, msg->header.timestamp);
}
if (true) {
bio.in_buffer.append((char*)video_data1, sizeof(video_data1));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_video());
EXPECT_EQ(0x00002af8, msg->header.timestamp);
}
if (true) {
bio.in_buffer.append((char*)audio_data2, sizeof(audio_data2));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_audio());
EXPECT_EQ(0x01002710, msg->header.timestamp);
}
if (true) {
bio.in_buffer.append((char*)video_data2, sizeof(video_data2));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_video());
EXPECT_EQ(0x01002710, msg->header.timestamp);
}
}
/**
* 2 audio packet, fmt 1/2
* first audio packet: dts:10000
* second audio packet: dts : 16787216 delta: 16777216
*/
VOID TEST(ProtocolStackTest, ProtocolRecvAVExtTimedeltaAudio)
{
srs_error_t err = srs_success;
MockBufferIO bio;
SrsProtocol proto(&bio);
// audio message
uint8_t audio_data1[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x03, // fmt 0
0x00, 0x27, 0x10, // timestamp 10000
0x00, 0x00, 0x80, // length, 128
0x08, // message_type
0x00, 0x00, 0x00, 0x00, // stream_id
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
uint8_t audio_data2[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x43, // fmt 1
0xff, 0xff, 0xff, // means extended timestamp
0x00, 0x00, 0x80, // length, 128
0x08, // message_type
0x01, 0x00, 0x00, 0x00, // extended timestamp delta:16777216
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
if (true) {
bio.in_buffer.append((char*)audio_data1, sizeof(audio_data1));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_audio());
EXPECT_EQ(0x00002710, msg->header.timestamp);
}
if (true) {
bio.in_buffer.append((char*)audio_data2, sizeof(audio_data2));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_audio());
EXPECT_EQ(0x01002710, msg->header.timestamp);
}
}
/**
* 2 video packet, fmt 1/2
* first video packet: dts:11000
* second video packet: dts : 16787216 delta: 16776216
*/
VOID TEST(ProtocolStackTest, ProtocolRecvAVExtTimedeltaVideo)
{
srs_error_t err = srs_success;
MockBufferIO bio;
SrsProtocol proto(&bio);
// video message
uint8_t video_data1[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x04, // fmt 0
0x00, 0x2a, 0xf8, // timestamp 11000
0x00, 0x00, 0x80, // length, 128
0x09, // message_type
0x00, 0x00, 0x00, 0x01, // stream_id
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
uint8_t video_data2[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x44, // fmt 1
0xff, 0xff, 0xff, // means extended timestamp
0x00, 0x00, 0x80, // length, 128
0x09, // message_type
0x00, 0xff, 0xfc, 0x18, // extended timestamp delta:16776216
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
};
if (true) {
bio.in_buffer.append((char*)video_data1, sizeof(video_data1));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_video());
EXPECT_EQ(0x00002af8, msg->header.timestamp);
}
if (true) {
bio.in_buffer.append((char*)video_data2, sizeof(video_data2));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_video());
EXPECT_EQ(0x01002710, msg->header.timestamp);
}
}
/**
* 2 video packet, fmt 3
* first video packet: dts:11000
* second video packet: dts : 16787216 delta: 16776216
*/
VOID TEST(ProtocolStackTest, ProtocolRecvAVExtTimedeltaVideoFmt3)
{
srs_error_t err = srs_success;
MockBufferIO bio;
SrsProtocol proto(&bio);
// video message
uint8_t video_data1[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x04, // fmt 0
0x00, 0x2a, 0xf8, // timestamp 11000
0x00, 0x01, 0x00, // length, 256
0x09, // message_type
0x00, 0x00, 0x00, 0x01, // stream_id
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
// chunk #2
0xC4, // fmt 3
/*next chunk.*/ 0x61, 0x79, 0x65, 0x72,
0x2e, 0x73, 0x77, 0x66, 0x3f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x31, 0x2e,
0x32, 0x33, 0x00, 0x05, 0x74, 0x63, 0x55, 0x72, 0x6c, 0x02, 0x00, 0x14, 0x72, 0x74, 0x6d, 0x70,
0x3a, 0x2f, 0x2f, 0x64, 0x65, 0x76, 0x3a, 0x31, 0x39, 0x33, 0x35, 0x2f, 0x6c, 0x69, 0x76, 0x65,
0x00, 0x04, 0x66, 0x70, 0x61, 0x64, 0x01, 0x00, 0x00, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69,
0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x00, 0x40, 0x6d, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x73, 0x00, 0x40, 0xab, 0xee,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x43, 0x6f, 0x64, 0x65,
0x63, 0x73, 0x00, 0x40, 0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
uint8_t video_data2[] = {
// 12bytes header, 1byts chunk header, 11bytes msg heder
0x44, // fmt 1
0xff, 0xff, 0xff, // means extended timestamp
0x00, 0x01, 0x10, // length, 272
0x09, // message_type
0x00, 0xff, 0xfc, 0x18, // extended timestamp delta:16776216
// msg payload start
0x02, 0x00, 0x07, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x03, 0x61, 0x70, 0x70, 0x02, 0x00, 0x04, 0x6c, 0x69, 0x76, 0x65, 0x00, 0x08, 0x66, 0x6c,
0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x57, 0x49, 0x4e, 0x20, 0x31, 0x32, 0x2c,
0x30, 0x2c, 0x30, 0x2c, 0x34, 0x31, 0x00, 0x06, 0x73, 0x77, 0x66, 0x55, 0x72, 0x6c, 0x02, 0x00,
0x51, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x73, 0x73, 0x72,
0x73, 0x2e, 0x6e, 0x65, 0x74, 0x3a, 0x38, 0x30, 0x38, 0x35, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x2f, 0x73, 0x72, 0x73, 0x5f, 0x70, 0x6c,
// chunk #2
0xC4, // fmt 3
0x00, 0xff, 0xfc, 0x18, // extended timestamp delta:16776216
/*next chunk.*/ 0x61, 0x79, 0x65, 0x72,
0x2e, 0x73, 0x77, 0x66, 0x3f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x31, 0x2e,
0x32, 0x33, 0x00, 0x05, 0x74, 0x63, 0x55, 0x72, 0x6c, 0x02, 0x00, 0x14, 0x72, 0x74, 0x6d, 0x70,
0x3a, 0x2f, 0x2f, 0x64, 0x65, 0x76, 0x3a, 0x31, 0x39, 0x33, 0x35, 0x2f, 0x6c, 0x69, 0x76, 0x65,
0x00, 0x04, 0x66, 0x70, 0x61, 0x64, 0x01, 0x00, 0x00, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69,
0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x00, 0x40, 0x6d, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x73, 0x00, 0x40, 0xab, 0xee,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x43, 0x6f, 0x64, 0x65,
0x63, 0x73, 0x00, 0x40, 0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// chunk #2
0xC4,
/*next chunk.*/
0x00, 0xff, 0xfc, 0x18, // extended timestamp delta:16776216
0x2e, 0x73, 0x77, 0x66, 0x3f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x31, 0x2e
};
if (true) {
bio.in_buffer.append((char*)video_data1, sizeof(video_data1));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_video());
EXPECT_EQ(0x00002af8, msg->header.timestamp);
}
if (true) {
bio.in_buffer.append((char*)video_data2, sizeof(video_data2));
SrsCommonMessage* msg_raw = NULL;
HELPER_ASSERT_SUCCESS(proto.recv_message(&msg_raw));
SrsUniquePtr<SrsCommonMessage> msg(msg_raw);
EXPECT_TRUE(msg->header.is_video());
EXPECT_EQ(0x01002710, msg->header.timestamp);
}
}
/**
* a video message, in 2 chunks packet.
* use 1B chunk header, min chunk id is 2.