1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

GB28181: Support GB28181-2016 protocol. v5.0.74 (#3201)

01. Support GB config as StreamCaster.
02. Support disable GB by --gb28181=off.
03. Add utests for SIP examples.
04. Wireshark plugin to decode TCP/9000 as rtp.rfc4571
05. Support MPEGPS program stream codec.
06. Add utest for PS stream codec.
07. Decode MPEGPS packet stream.
08. Carry RTP and PS packet as helper in PS message.
09. Support recover from error mode.
10. Support process by a pack of PS/TS messages.
11. Add statistic for recovered and msgs dropped.
12. Recover from err position fastly.
13. Define state machine for GB session.
14. Bind context to GB session.
15. Re-invite when media disconnected.
16. Update GitHub actions with GB28181.
17. Support parse CANDIDATE by env or pip.
18. Support mux GB28181 to RTMP.
19. Support regression test by srs-bench.
This commit is contained in:
Winlin 2022-10-06 17:40:58 +08:00 committed by GitHub
parent 9c81a0e1bd
commit 5a420ece3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
298 changed files with 43343 additions and 763 deletions

View file

@ -0,0 +1,315 @@
//
// Copyright (c) 2013-2022 The SRS Authors
//
// SPDX-License-Identifier: MIT or MulanPSL-2.0
//
#include <srs_utest_kernel2.hpp>
#include <srs_kernel_ps.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_rtc_rtcp.hpp>
#include <srs_app_gb28181.hpp>
VOID TEST(KernelPSTest, PsPacketDecodeNormal)
{
srs_error_t err = srs_success;
MockPsHandler handler;
SrsPsContext context;
// Payload of GB28181 camera PS stream, the first packet:
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=0, Time=0
if (true) {
SrsRtpPacket rtp;
if (true) {
string raw = string(
"\x80\x60\x00\x00\x00\x00\x00\x00\x0b\xeb\xdf\xa1\x00\x00\x01\xba" \
"\x44\x68\x6e\x4c\x94\x01\x01\x30\x13\xfe\xff\xff\x00\x00\xa0\x05" \
"\x00\x00\x01\xbb\x00\x12\x80\x98\x09\x04\xe1\x7f\xe0\xe0\x80\xc0" \
"\xc0\x08\xbd\xe0\x80\xbf\xe0\x80\x00\x00\x01\xbc\x00\x5e\xfc\xff" \
"\x00\x24\x40\x0e\x48\x4b\x01\x00\x16\x9b\xa5\x22\x2e\xf7\x00\xff" \
"\xff\xff\x41\x12\x48\x4b\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" \
"\x0a\x0b\x0c\x0d\x0e\x0f\x00\x30\x1b\xe0\x00\x1c\x42\x0e\x07\x10" \
"\x10\xea\x02\x80\x01\xe0\x11\x30\x00\x00\x1c\x20\x2a\x0a\x7f\xff" \
"\x00\x00\x07\x08\x1f\xfe\x50\x3c\x0f\xc0\x00\x0c\x43\x0a\x00\x90" \
"\xfe\x02\xb1\x13\x01\xf4\x03\xff\xcb\x85\x54\xb9\x00\x00\x01\xe0" \
"\x00\x26\x8c\x80\x07\x21\x1a\x1b\x93\x25\xff\xfc\x00\x00\x00\x01" \
"\x67\x4d\x00\x1e\x9d\xa8\x28\x0f\x69\xb8\x08\x08\x0a\x00\x00\x03" \
"\x00\x02\x00\x00\x03\x00\x65\x08\x00\x00\x01\xe0\x00\x0e\x8c\x00" \
"\x03\xff\xff\xfc\x00\x00\x00\x01\x68\xee\x3c\x80\x00\x00\x01\xe0" \
"\x00\x0e\x8c\x00\x02\xff\xfc\x00\x00\x00\x01\x06\xe5\x01\xba\x80" \
"\x00\x00\x01\xe0\x35\x62\x8c\x00\x02\xff\xf8\x00\x00\x00\x01\x65", 256) + string(1156, 'x');
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// There should be three video messages.
HELPER_ASSERT_SUCCESS(context.decode(&b, &handler));
EXPECT_EQ(3, handler.msgs_.size());
}
// We use the first packet bytes to mock the RTP packet seq 1 to 8.
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=1, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=2, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=3, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=4, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=5, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=6, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=7, Time=0
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=8, Time=0
for (int i = 0; i < 8; i++) {
SrsRtpPacket rtp;
if (true) {
string raw = string("\x80\x60\x00\x01\x00\x00\x00\x00\x0b\xeb\xdf\xa1", 12) + string(1400, 'x');
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// Bytes continuity for the large video frame, got nothing message yet.
HELPER_ASSERT_SUCCESS(context.decode(&b, handler.clear()));
EXPECT_EQ(0, handler.msgs_.size());
}
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=9, Time=0
if (true) {
SrsRtpPacket rtp;
if (true) {
string raw = string("\x80\x60\x00\x09\x00\x00\x00\x00\x0b\xeb\xdf\xa1", 12) + string(1300, 'x')
+ string("\x00\x00\x01\xbd\x00\x6a\x8c\x80\x07\x21\x1a\x1b\x93\x25\xff\xf8" \
"\x00\x02\x00\x17\x00\x01\x80\x00\x00\xff\xa0\x05\xe0\xf1\xf0\x50" \
"\x18\x52\xd6\x5c\xa2\x78\x90\x23\xf9\xf6\x64\xba\xc7\x90\x5e\xd3" \
"\x80\x2f\x29\xad\x06\xee\x14\x62\xec\x6f\x77\xaa\x71\x80\xb3\x50" \
"\xb8\xd1\x85\x7f\x44\x30\x4f\x44\xfd\xcd\x21\xe6\x55\x36\x08\x6c" \
"\xb8\xd1\x85\x7f\x44\x30\x4f\x44\xfd\xcd\x21\xe6\x55\x36\x08\x6c" \
"\xc9\xf6\x5c\x74", 100);
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// There should be one large video message, might be an I frame.
HELPER_ASSERT_SUCCESS(context.decode(&b, handler.clear()));
EXPECT_EQ(1, handler.msgs_.size());
}
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=10, Time=0
if (true) {
SrsRtpPacket rtp;
if (true) {
string raw("\x80\x60\x00\x0a\x00\x00\x00\x00\x0b\xeb\xdf\xa1" \
"\x57\xb3\xa3\xbc\x16\x2c\x3c\x9e\x69\x89\x48\xa4", 24);
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// There should be a message of private stream, we ignore it, so we won't get it in callback.
HELPER_ASSERT_SUCCESS(context.decode(&b, handler.clear()));
EXPECT_EQ(0, handler.msgs_.size());
}
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=11, Time=3600
if (true) {
SrsRtpPacket rtp;
if (true) {
string raw = string("\x80\x60\x00\x0b\x00\x00\x0e\x10\x0b\xeb\xdf\xa1", 12)
+ string("\x00\x00\x01\xc0" \
"\x00\x82\x8c\x80\x09\x21\x1a\x1b\xa3\x51\xff\xff\xff\xf8\xff\xf9" \
"\x50\x40\x0e\xdf\xfc\x01\x2c\x2e\x84\x28\x23\x0a\x85\x82\xa2\x40" \
"\x90\x50\x2c\x14\x0b\x05\x42\x41\x30\x90\x44\x28\x16\x08\x84\x82", 52)
+ string(84, 'x');
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// There should be one audio message.
HELPER_ASSERT_SUCCESS(context.decode(&b, handler.clear()));
EXPECT_EQ(1, handler.msgs_.size());
}
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=12, Time=3600
if (true) {
SrsRtpPacket rtp;
if (true) {
string raw = string("\x80\x60\x00\x0c\x00\x00\x0e\x10\x0b\xeb\xdf\xa1", 12)
+ string("\x00\x00\x01\xc0" \
"\x00\x8a\x8c\x80\x09\x21\x1a\x1b\xb3\x7d\xff\xff\xff\xf8\xff\xf9" \
"\x50\x40\x0f\xdf\xfc\x01\x2c\x2e\x88\x2a\x13\x0a\x09\x82\x41\x10" \
"\x90\x58\x26\x14\x13\x05\x02\xc2\x10\xa0\x58\x4a\x14\x0a\x85\x02", 52)
+ string(92, 'x');
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// There should be another audio message.
HELPER_ASSERT_SUCCESS(context.decode(&b, handler.clear()));
EXPECT_EQ(1, handler.msgs_.size());
}
// PT=DynamicRTP-Type-96, SSRC=0xBEBDFA1, Seq=13, Time=3600
if (true) {
SrsRtpPacket rtp;
if (true) {
string raw = string("\x80\x60\x00\x0d\x00\x00\x0e\x10\x0b\xeb\xdf\xa1", 12)
+ string("\x00\x00\x01\xba" \
"\x44\x68\x6e\xbd\x14\x01\x01\x30\x13\xfe\xff\xff\x00\x00\xa0\x06" \
"\x00\x00\x01\xe0\x03\x4a\x8c\x80\x08\x21\x1a\x1b\xaf\x45\xff\xff" \
"\xf8\x00\x00\x00\x01\x61\xe0\x08\xbf\x3c\xb6\x63\x68\x4b\x7f\xea", 52)
+ string(816, 'x');
SrsBuffer b((char*)raw.data(), raw.length());
HELPER_ASSERT_SUCCESS(rtp.decode(&b));
}
SrsRtpRawPayload* rtp_raw = dynamic_cast<SrsRtpRawPayload*>(rtp.payload());
SrsBuffer b((char*)rtp_raw->payload, rtp_raw->nn_payload);
// There should be another audio message.
HELPER_ASSERT_SUCCESS(context.decode(&b, handler.clear()));
EXPECT_EQ(1, handler.msgs_.size());
}
}
VOID TEST(KernelPSTest, PsPacketHeaderClockDecode)
{
srs_error_t err = srs_success;
SrsPsContext context;
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x44\x68\x6e\x4c\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x00686c992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x64\x68\x6e\x4c\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x10686c992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\x68\x6e\x4c\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18686c992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe8\x6e\x4c\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e86c992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\x6e\x4c\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e96c992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\x4c\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9ec992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xcc\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9ed992, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdc\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edb92, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x94\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb2, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x9c\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb3, pkt.system_clock_reference_base_);
EXPECT_EQ(0, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x9e\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb3, pkt.system_clock_reference_base_);
EXPECT_EQ(0x100, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x9f\x01"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb3, pkt.system_clock_reference_base_);
EXPECT_EQ(0x180, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x9f\x11"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb3, pkt.system_clock_reference_base_);
EXPECT_EQ(0x188, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x9f\x19"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb3, pkt.system_clock_reference_base_);
EXPECT_EQ(0x18c, pkt.system_clock_reference_extension_);
}
if(true) {
SrsPsPacket pkt(&context);
SrsBuffer b((char*)"\x00\x00\x01\xba"/*start*/ "\x74\xe9\xee\xdd\x9f\x1b"/*clock*/ "\x01\x30\x13\xf8"/*mux*/, 14);
HELPER_ASSERT_SUCCESS(pkt.decode(&b));
EXPECT_EQ(0x18e9edbb3, pkt.system_clock_reference_base_);
EXPECT_EQ(0x18d, pkt.system_clock_reference_extension_);
}
}