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

@ -307,7 +307,15 @@
XX(ERROR_HTTPS_HANDSHAKE , 4042, "HttpsHandshake", "Failed to do handshake for HTTPS") \
XX(ERROR_HTTPS_READ , 4043, "HttpsRead", "Failed to read data from HTTPS stream") \
XX(ERROR_HTTPS_WRITE , 4044, "HttpsWrite", "Failed to write data to HTTPS stream") \
XX(ERROR_HTTPS_KEY_CRT , 4045, "HttpsSslFile", "Failed to load SSL key or crt file for HTTPS")
XX(ERROR_HTTPS_KEY_CRT , 4045, "HttpsSslFile", "Failed to load SSL key or crt file for HTTPS") \
XX(ERROR_GB_SIP_HEADER , 4046, "GbHeaderCallId", "Missing field of SIP header for GB28181") \
XX(ERROR_GB_SIP_MESSAGE , 4047, "GbHeaderCallId", "Invalid SIP message for GB28181") \
XX(ERROR_GB_PS_HEADER , 4048, "GbPsHeader", "Invalid PS header for GB28181") \
XX(ERROR_GB_PS_PSE , 4049, "GbPsPSE", "Invalid PS PSE for GB28181") \
XX(ERROR_GB_PS_MEDIA , 4050, "GbPsMedia", "Invalid PS Media packet for GB28181") \
XX(ERROR_GB_SSRC_GENERATE , 4051, "GbSsrcGenerate", "Failed to generate SSRC for GB28181") \
XX(ERROR_GB_CONFIG , 4052, "GbConfig", "Invalid configuration for GB28181") \
XX(ERROR_GB_TIMEOUT , 4053, "GbTimeout", "SIP or media connection timeout for GB28181") \
/**************************************************/
/* RTC protocol error. */

View file

@ -0,0 +1,491 @@
//
// Copyright (c) 2013-2022 The SRS Authors
//
// SPDX-License-Identifier: MIT or MulanPSL-2.0
//
#include <srs_kernel_ps.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_kernel_utility.hpp>
#include <string>
using namespace std;
// The minimum required bytes to parse a PS packet.
#define SRS_PS_MIN_REQUIRED 32
SrsPsDecodeHelper::SrsPsDecodeHelper()
{;
rtp_seq_ = 0;
rtp_ts_ = 0;
rtp_pt_ = 0;
pack_id_ = 0;
pack_first_seq_ = 0;
pack_pre_msg_last_seq_ = 0;
pack_nn_msgs_ = 0;
ctx_ = NULL;
ps_ = NULL;
}
ISrsPsMessageHandler::ISrsPsMessageHandler()
{
}
ISrsPsMessageHandler::~ISrsPsMessageHandler()
{
}
SrsPsContext::SrsPsContext()
{
last_ = NULL;
current_ = NULL;
helper_.ctx_ = this;
detect_ps_integrity_ = false;
}
SrsPsContext::~SrsPsContext()
{
srs_freep(last_);
srs_freep(current_);
}
void SrsPsContext::set_detect_ps_integrity(bool v)
{
detect_ps_integrity_ = v;
}
SrsTsMessage* SrsPsContext::last()
{
if (!last_) {
last_ = new SrsTsMessage();
last_->ps_helper_ = &helper_;
}
return last_;
}
SrsTsMessage* SrsPsContext::reap()
{
SrsTsMessage* msg = last_;
last_ = new SrsTsMessage();
last_->ps_helper_ = &helper_;
return msg;
}
srs_error_t SrsPsContext::decode(SrsBuffer* stream, ISrsPsMessageHandler* handler)
{
srs_error_t err = srs_success;
// Decode PS packet one by one.
while (!stream->empty()) {
// If new PS packet but not enough packet, ignore.
if (detect_ps_integrity_ && stream->left() >= 4) {
uint8_t* p = (uint8_t*)stream->head();
if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && stream->left() <= SRS_PS_MIN_REQUIRED) {
break;
}
}
// Try to decode the stream by one PS packet.
// See Table 2-32 Program Stream pack, hls-mpeg-ts-iso13818-1.pdf, page 73
if ((err = do_decode(stream, handler)) != srs_success) {
return srs_error_wrap(err, "decode");
}
// Use unit start as 1, however it has no effect because PES_packet_length should never be 0 for PS packet.
const int payload_unit_start_indicator = 1;
if (!last()->completed(payload_unit_start_indicator)) {
continue; // Ignore if message not completed.
}
// Reap the last completed PS message.
SrsTsMessage* msg = reap();
SrsAutoFree(SrsTsMessage, msg);
if (msg->sid == SrsTsPESStreamIdProgramStreamMap) {
if (!msg->payload || !msg->payload->length()) {
return srs_error_new(ERROR_GB_PS_HEADER, "empty PSM payload");
}
// Decode PSM(Program Stream map) from PES packet payload.
SrsBuffer buf(msg->payload->bytes(), msg->payload->length());
SrsPsPsmPacket psm;
if ((err = psm.decode(&buf)) != srs_success) {
return srs_error_wrap(err, "decode psm");
}
srs_info("PS: Ignore PSM for video=%#x, audio=%#x", psm.video_elementary_stream_id_, psm.audio_elementary_stream_id_);
//context_->set(psm.video_elementary_stream_id_, SrsTsPidApplyVideo);
//context_->set(psm.audio_elementary_stream_id_, SrsTsPidApplyAudio);
} else if (msg->is_video() || msg->is_audio()) {
// Update the total messages in pack.
helper_.pack_pre_msg_last_seq_ = helper_.rtp_seq_;
helper_.pack_nn_msgs_++;
//srs_error("PS: Got message %s, dts=%" PRId64 ", payload=%dB", msg->is_video() ? "Video" : "Audio", msg->dts/9000, msg->PES_packet_length);
if (handler && (err = handler->on_ts_message(msg)) != srs_success) {
return srs_error_wrap(err, "handle PS message");
}
} else {
srs_info("PS: Ignore message sid=%#x", msg->sid);
}
}
return err;
}
srs_error_t SrsPsContext::do_decode(SrsBuffer* stream, ISrsPsMessageHandler* handler)
{
srs_error_t err = srs_success;
// If last message not completed, the bytes in stream must be payload.
if (!last()->fresh()) {
if ((err = last()->dump(stream, NULL)) != srs_success) {
return srs_error_wrap(err, "dump pes");
}
return err;
}
// For PS pack, must always start with 00 00 01 XX.
// See Table 2-32 Program Stream pack, hls-mpeg-ts-iso13818-1.pdf, page 73
if (!stream->require(4)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
}
uint8_t* p = (uint8_t*)stream->head();
// For normal mode, should start with 00 00 01, for pack or system header or PES packet.
if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01) {
return srs_error_new(ERROR_GB_PS_HEADER, "Invalid PS stream %#x %#x %#x", p[0], p[1], p[2]);
}
// If pack start code, it's a net PS pack stream.
if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xba) {
srs_freep(current_);
}
if (!current_) {
current_ = new SrsPsPacket(this);
current_->id_ |= helper_.rtp_seq_; // The low 16 bits is reserved for RTP seq.
helper_.pack_id_ = current_->id_;
helper_.pack_first_seq_ = helper_.rtp_seq_;
// Set the helper for decoder, pass-by values.
helper_.ps_ = current_;
helper_.pack_nn_msgs_ = 0;
}
// Try to decode the PS pack stream.
int pos = stream->pos();
if ((err = current_->decode(stream)) != srs_success) {
err = srs_error_wrap(err, "decode start=%d, pos=%d, left=%d", pos, stream->pos(), stream->left());
stream->skip(pos - stream->pos());
return err;
}
return err;
}
SrsPsPacket::SrsPsPacket(SrsPsContext* context)
{
context_ = context;
has_pack_header_ = has_system_header_ = false;
static uint32_t gid = 0;
id_ = ((gid++) << 16) & 0xffff0000;
pack_start_code_ = 0;
system_clock_reference_base_ = 0;
system_clock_reference_extension_ = 0;
program_mux_rate_ = 0;
pack_stuffing_length_ = 0;
system_header_start_code_ = 0;
header_length_ = 0;
rate_bound_ = 0;
audio_bound_ = 0;
CSPS_flag_ = 0;
system_audio_lock_flag_ = 0;
system_video_lock_flag_ = 0;
video_bound_ = 0;
packet_rate_restriction_flag_ = 0;
audio_stream_id_ = 0;
audio_buffer_bound_scale_ = 0;
audio_buffer_size_bound_ = 0;
video_stream_id_ = 0;
video_buffer_bound_scale_ = 0;
video_buffer_size_bound_ = 0;
}
SrsPsPacket::~SrsPsPacket()
{
}
srs_error_t SrsPsPacket::decode(SrsBuffer* stream)
{
srs_error_t err = srs_success;
// Program Stream pack header.
if (!stream->require(4)) return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
uint8_t* p = (uint8_t*)stream->head();
if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xba) {
if ((err = decode_pack(stream)) != srs_success) {
return srs_error_wrap(err, "pack");
}
has_pack_header_ = true;
}
// Program stream system header.
if (stream->empty()) return err; // Parsed done, OK.
if (!stream->require(4)) return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
p = (uint8_t*)stream->head();
if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xbb) {
if ((err = decode_system(stream)) != srs_success) {
return srs_error_wrap(err, "system");
}
has_system_header_ = true;
}
// Packet start code prefix.
while (!stream->empty()) {
if (!stream->require(4)) return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
p = (uint8_t*)stream->head();
if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01) break;
if (p[3] == 0xba || p[3] == 0xbb) break; // Reparse for pack or system header.
SrsMpegPES pes;
if ((err = pes.decode(stream)) != srs_success) {
return srs_error_wrap(err, "decode pes");
}
SrsTsMessage* lm = context_->last();
// The stream id should never change for PS stream.
if (lm->sid != (SrsTsPESStreamId)0 && lm->sid != (SrsTsPESStreamId)pes.stream_id) {
return srs_error_new(ERROR_GB_PS_PSE, "PS stream id change from %#x to %#x", lm->sid, pes.stream_id);
}
lm->sid = (SrsTsPESStreamId)pes.stream_id;
if (pes.PTS_DTS_flags == 0x02 || pes.PTS_DTS_flags == 0x03) {
lm->dts = pes.dts;
lm->pts = pes.pts;
}
if (pes.has_payload_) {
// The size of PS message, should be always a positive value.
lm->PES_packet_length = pes.nb_payload_;
if ((err = lm->dump(stream, &pes.nb_bytes)) != srs_success) {
return srs_error_wrap(err, "dump pes");
}
}
// Use unit start as 1, however it has no effect because PES_packet_length should never be 0 for PS packet.
const int payload_unit_start_indicator = 1;
if (lm->completed(payload_unit_start_indicator)) {
return err; // OK, got one message, let PS context handle it.
}
}
return err;
}
srs_error_t SrsPsPacket::decode_pack(SrsBuffer* stream)
{
srs_error_t err = srs_success;
// 14 bytes fixed header.
if (!stream->require(14)) {
return srs_error_new(ERROR_GB_PS_HEADER, "ps requires 14 only %d bytes", stream->left());
}
pack_start_code_ = stream->read_4bytes();
srs_assert(pack_start_code_ == 0x000001ba);
uint64_t r0 = stream->read_4bytes();
uint16_t r1 = stream->read_2bytes();
system_clock_reference_extension_ = (r1 >> 1) & 0x1ff;
system_clock_reference_base_ = 0x00
| ((uint64_t) ((r0 >> 27) & 0x07) << 30) // 3bits
| ((uint64_t) ((r0 >> 11) & 0x7fff) << 15) // 15bits
| ((uint64_t) (r0 & 0x03ff) << 5) // 10bits
| (uint64_t) ((r1 >> 11) & 0x1f); // 5bits
program_mux_rate_ = stream->read_3bytes();
program_mux_rate_ = (program_mux_rate_ >> 2) & 0x3fffff;
pack_stuffing_length_ = stream->read_1bytes();
pack_stuffing_length_ &= 0x07;
//srs_warn("PS: New pack header clock=%" PRId64 ", rate=%d", system_clock_reference_base_, program_mux_rate_);
if (!stream->require(pack_stuffing_length_)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", pack_stuffing_length_, stream->left());
}
stream->skip(pack_stuffing_length_);
return err;
}
srs_error_t SrsPsPacket::decode_system(SrsBuffer* stream)
{
srs_error_t err = srs_success;
system_header_start_code_ = stream->read_4bytes();
srs_assert(system_header_start_code_ == 0x000001bb);
if (!stream->require(8)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 8 only %d bytes", stream->left());
}
header_length_ = stream->read_2bytes();
if (!stream->require(header_length_)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", header_length_, stream->left());
}
SrsBuffer b(stream->head(), header_length_);
stream->skip(header_length_);
rate_bound_ = b.read_3bytes();
rate_bound_ = (rate_bound_ >> 1) & 0x3fffff;
CSPS_flag_ = b.read_1bytes();
audio_bound_ = (CSPS_flag_ >> 2) & 0x3f;
CSPS_flag_ &= 0x01;
video_bound_ = b.read_1bytes();
system_audio_lock_flag_ = (video_bound_ >> 7) & 0x01;
system_video_lock_flag_ = (video_bound_ >> 6) & 0x01;
video_bound_ &= 0x1f;
packet_rate_restriction_flag_ = b.read_1bytes();
packet_rate_restriction_flag_ = (packet_rate_restriction_flag_ >> 5) & 0x01;
//srs_warn("PS: New system header rate_bound=%d, video_bound=%d, audio_bound=%d", rate_bound_, video_bound_, audio_bound_);
// Parse stream_id and buffer information.
while (!b.empty()) {
uint8_t r2 = (uint8_t) b.head()[0];
if ((r2 & 0x80) != 0x80) break;
if (!b.require(3)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 3 only %d bytes", b.left());
}
SrsTsPESStreamId stream_id = (SrsTsPESStreamId)(uint8_t)b.read_1bytes();
uint16_t buffer_size_bound = b.read_2bytes();
uint8_t buffer_bound_scale = (uint8_t)((buffer_size_bound>>13) & 0x01);
buffer_size_bound &= 0x1fff;
if (((stream_id>>4) & 0x0f) == SrsTsPESStreamIdVideoChecker) {
video_stream_id_ = stream_id;
video_buffer_bound_scale_ = buffer_bound_scale;
video_buffer_size_bound_ = buffer_size_bound;
} else if (((stream_id>>5) & 0x07) == SrsTsPESStreamIdAudioChecker) {
audio_stream_id_ = stream_id;
audio_buffer_bound_scale_ = buffer_bound_scale;
audio_buffer_size_bound_ = buffer_size_bound;
} else {
srs_info("PS: Ignore stream_id=%#x, buffer_bound_scale=%d, buffer_size_bound=%d", stream_id, buffer_bound_scale, buffer_size_bound);
}
}
return err;
}
SrsPsPsmPacket::SrsPsPsmPacket()
{
current_next_indicator_ = 0;
program_stream_map_version_ = 0;
program_stream_info_length_ = 0;
elementary_stream_map_length_ = 0;
video_stream_type_ = 0;
video_elementary_stream_id_ = 0;
video_elementary_stream_info_length_ = 0;
audio_stream_type_ = 0;
audio_elementary_stream_id_ = 0;
audio_elementary_stream_info_length_ = 0;
CRC_32_ = 0;
}
SrsPsPsmPacket::~SrsPsPsmPacket()
{
}
srs_error_t SrsPsPsmPacket::decode(SrsBuffer* stream)
{
srs_error_t err = srs_success;
// From first util program_stream_info_length field, at least 4 bytes.
if (!stream->require(4)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
}
uint16_t r0 = stream->read_2bytes();
if ((r0&0x01) != 0x01) {
return srs_error_new(ERROR_GB_PS_HEADER, "invalid marker of 0x%#x", r0);
}
program_stream_map_version_ = (uint8_t)(r0&0x1f);
current_next_indicator_ = (uint8_t)((r0>>7) & 0x01);
if (!current_next_indicator_) {
return srs_error_new(ERROR_GB_PS_HEADER, "invalid indicator of 0x%#x", r0);
}
program_stream_info_length_ = stream->read_2bytes();
if (!stream->require(program_stream_info_length_)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", program_stream_info_length_, stream->left());
}
stream->skip(program_stream_info_length_);
// The number of ES map count, 2 bytes.
if (!stream->require(2)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 2 only %d bytes", stream->left());
}
elementary_stream_map_length_ = stream->read_2bytes();
if (!stream->require(elementary_stream_map_length_)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", elementary_stream_map_length_, stream->left());
}
SrsBuffer b(stream->head(), elementary_stream_map_length_);
stream->skip(elementary_stream_map_length_);
while (!b.empty()) {
if (!b.require(4)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", b.left());
}
SrsTsStream stream_type = (SrsTsStream)(uint8_t)b.read_1bytes();
uint8_t elementary_stream_id = b.read_1bytes();
uint16_t elementary_stream_info_length = b.read_2bytes();
if (!b.require(elementary_stream_info_length)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", elementary_stream_info_length, b.left());
}
// Descriptor defined as bellow section, but we ignore it:
// Table 2-40 Video stream descriptor, hls-mpeg-ts-iso13818-1.pdf, page 82
// Table 2-42 Audio stream descriptor, hls-mpeg-ts-iso13818-1.pdf, page 83
b.skip(elementary_stream_info_length);
srs_info("PS: Ignore %d bytes descriptor for stream=%#x", elementary_stream_info_length, stream_type);
if (stream_type == SrsTsStreamVideoH264) {
video_stream_type_ = stream_type;
video_elementary_stream_id_ = elementary_stream_id;
video_elementary_stream_info_length_ = elementary_stream_info_length;
} else if (stream_type == SrsTsStreamAudioAAC) {
audio_stream_type_ = stream_type;
audio_elementary_stream_id_ = elementary_stream_id;
audio_elementary_stream_info_length_ = elementary_stream_info_length;
} else {
srs_trace("PS: Ignore stream_type=%#x, es_id=%d, es_info=%d", stream_type, elementary_stream_id, elementary_stream_info_length);
}
}
// The last CRC32.
if (!stream->require(4)) {
return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
}
CRC_32_ = stream->read_4bytes();
return err;
}

View file

@ -0,0 +1,314 @@
//
// Copyright (c) 2013-2022 The SRS Authors
//
// SPDX-License-Identifier: MIT or MulanPSL-2.0
//
#ifndef SRS_KERNEL_PS_HPP
#define SRS_KERNEL_PS_HPP
#include <srs_core.hpp>
#include <srs_kernel_ts.hpp>
class SrsPsPacket;
class SrsPsContext;
// The helper for PS decoding.
struct SrsPsDecodeHelper
{
public:
// For debugging to get the RTP packet source. Not used in context.
uint16_t rtp_seq_;
// For debugging to get the RTP packet timestamp. Not used in context.
uint32_t rtp_ts_;
// For debugging to get the RTP packet payload type. Not used in context.
uint8_t rtp_pt_;
public:
// For debugging, current pack id. Not used in context.
uint32_t pack_id_;
// For debugging, the first sequence of current pack. Not used in context.
uint16_t pack_first_seq_;
// For debugging, the last sequence of previous message in current pack. Not used in context.
uint16_t pack_pre_msg_last_seq_;
// For debugging, the number of messages in pack. Not used in context.
uint16_t pack_nn_msgs_;
public:
// The PS context for decoding.
SrsPsContext* ctx_;
// The PS packet for decoding.
SrsPsPacket* ps_;
public:
SrsPsDecodeHelper();
};
// The PS message handler.
class ISrsPsMessageHandler : public ISrsTsHandler
{
public:
ISrsPsMessageHandler();
virtual ~ISrsPsMessageHandler();
public:
// When enter recover mode, user should drop all messages in pack. The nn_recover indicates the number of retry
// during recovery, that is 0 for the first time, and 1 for the second time.
virtual void on_recover_mode(int nn_recover) = 0;
};
// The PS context, to process PS PES stream.
class SrsPsContext
{
public:
SrsPsDecodeHelper helper_;
private:
// The last decoding PS(TS) message.
SrsTsMessage* last_;
// The current parsing PS packet context.
SrsPsPacket* current_;
// Whether detect PS packet header integrity.
bool detect_ps_integrity_;
public:
SrsPsContext();
virtual ~SrsPsContext();
public:
// Set whether detecting PS header integrity.
void set_detect_ps_integrity(bool v);
// Get the last PS(TS) message. Create one if not exists.
SrsTsMessage* last();
// Reap the last message and create a fresh one.
SrsTsMessage* reap();
public:
// Feed with ts packets, decode as ts message, callback handler if got one ts message.
// A ts video message can be decoded to NALUs by SrsRawH264Stream::annexb_demux.
// A ts audio message can be decoded to RAW frame by SrsRawAacStream::adts_demux.
// @param handler The ts message handler to process the msg.
// @remark We will consume all bytes in stream.
virtual srs_error_t decode(SrsBuffer* stream, ISrsPsMessageHandler* handler);
private:
srs_error_t do_decode(SrsBuffer* stream, ISrsPsMessageHandler* handler);
};
// The packet in ps stream.
// 2.5.3.3 Pack layer of Program Stream, hls-mpeg-ts-iso13818-1.pdf, page 73
class SrsPsPacket
{
public:
SrsPsContext* context_;
public:
// The global ID of pack header. The low 16 bits is reserved for seq. Automatically generate the high bits in
// constructor.
uint32_t id_;
// Whether the PS pack stream has pack and system header.
bool has_pack_header_;
bool has_system_header_;
// Table 2-33 Program Stream pack header, hls-mpeg-ts-iso13818-1.pdf, page 73
public:
// 4B
// The pack_start_code is the bit string '0000 0000 0000 0000 0000 0001 1011 1010' (0x000001BA). It identifies the
// beginning of a pack.
uint32_t pack_start_code_; // 32bits
// 6B
// 2bits const '01'
// 3bits system_clock_reference_base [32..30]
// 1bit marker_bit '1'
// 15bits system_clock_reference_base [29..15]
// 1bit marker_bit '1'
// 22bits system_clock_reference_base [14..0]
// 1bit marker_bit '1'
// 9bits system_clock_reference_extension
// 1bit marker_bit '1'
// The system clock reference (SCR) is a 42-bit field coded in two parts. The first part,
// system_clock_reference_base, is a 33-bit field whose value is given by SCR_base(i) as given in equation 2-19.
// The second part, system_clock_reference_extension, is a 9-bit field whose value is given by SCR_ext(i), as given
// in equation 2-20. The SCR indicates the intended time of arrival of the byte containing the last bit of the
// system_clock_reference_base at the input of the program target decoder.
uint64_t system_clock_reference_base_; // 32bits
uint16_t system_clock_reference_extension_; // 9bits
// 3B
// 22bits program_mux_rate
// 1bit marker_bit '1'
// 1bit marker_bit '1'
// This is a 22-bit integer specifying the rate at which the P-STD receives the Program Stream during the pack in
// which it is included. The value of program_mux_rate is measured in units of 50 bytes/second. The value 0 is
// forbidden. The value represented in program_mux_rate is used to define the time of arrival of bytes at the input
// to the P-STD in 2.5.2. The value encoded in the program_mux_rate field may vary from pack to pack in an ITU-T
// Rec. H.222.0 | ISO/IEC 13818-1 program multiplexed stream.
uint32_t program_mux_rate_; // 22bits
// 1B
// 5bits reserved
// 3bits pack_stuffing_length
// A 3-bit integer specifying the number of stuffing bytes which follow this field.
uint8_t pack_stuffing_length_; // 3bits
// Table 2-34 Program Stream system header, hls-mpeg-ts-iso13818-1.pdf, page 74
public:
// 4B
// The system_header_start_code is the bit string '0000 0000 0000 0000 0000 0001 1011 1011' (0x000001BB). It
// identifies the beginning of a system header.
uint32_t system_header_start_code_;
// 2B
// This 16-bit field indicates the length in bytes of the system header following the header_length field. Future
// extensions of this Specification may extend the system header.
uint16_t header_length_;
// 3B
// 1bit marker_bit '1'
// 22bits rate_bound
// 1bit marker_bit '1'
// A 22-bit field. The rate_bound is an integer value greater than or equal to the maximum value of the
// program_mux_rate field coded in any pack of the Program Stream. It may be used by a decoder to assess whether it
// is capable of decoding the entire stream.
uint32_t rate_bound_;
// 1B
// 6bits audio_bound
// 1bit fixed_flag
// 1bit CSPS_flag
// A 6-bit field. The audio_bound is an integer in the inclusive range from 0 to 32 and is set to a value greater
// than or equal to the maximum number of ISO/IEC 13818-3 and ISO/IEC 11172-3 audio streams in the Program Stream
// for which the decoding processes are simultaneously active. For the purpose of this subclause, the decoding
// process of an ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream is active if the STD buffer is not empty or if a
// Presentation Unit is being presented in the P-STD model.
uint8_t audio_bound_;
// The CSPS_flag is a 1-bit field. If its value is set to '1' the Program Stream meets the constraints defined in
// 2.7.9.
uint8_t CSPS_flag_;
// 1B
// 1bit system_audio_lock_flag
// 1bit system_video_lock_flag
// 1bit marker_bit '1'
// 5bits video_bound
// The system_audio_lock_flag is a 1-bit field indicating that there is a specified, constant rational relationship
// between the audio sampling rate and the system_clock_frequency in the system target decoder. The
// system_clock_frequency is defined in 2.5.2.1 and the audio sampling rate is specified in ISO/IEC 13818-3. The
// system_audio_lock_flag may only be set to '1' if, for all presentation units in all audio elementary streams in
// the Program Stream, the ratio of system_clock_frequency to the actual audio sampling rate, SCASR, is constant and
// equal to the value indicated in the following table at the nominal sampling rate indicated in the audio stream.
uint8_t system_audio_lock_flag_;
// The system_video_lock_flag is a 1-bit field indicating that there is a specified, constant rational relationship
// between the video frame rate and the system clock frequency in the system target decoder. Subclause 2.5.2.1
// defines system_clock_frequency and the video frame rate is specified in ITU-T Rec. H.262 | ISO/IEC 13818-2. The
// system_video_lock_flag may only be set to '1' if, for all presentation units in all video elementary streams in
// the ITU-T Rec. H.222.0 | ISO/IEC 13818-1 program, the ratio of system_clock_frequency to the actual video frame
// rate, SCFR, is constant and equal to the value indicated in the following table at the nominal frame rate
// indicated in the video stream.
uint8_t system_video_lock_flag_;
// The video_bound is a 5-bit integer in the inclusive range from 0 to 16 and is set to a value greater than or
// equal to the maximum number of ITU-T Rec. H.262 | ISO/IEC 13818-2 and ISO/IEC 11172-2 streams in the Program
// Stream of which the decoding processes are simultaneously active. For the purpose of this subclause, the decoding
// process of an ITU-T Rec. H.262 | ISO/IEC 13818-2 and ISO/IEC 11172-2 video stream is active if the P-STD buffer
// is not empty, or if a Presentation Unit is being presented in the P-STD model, or if the reorder buffer is not
// empty.
uint8_t video_bound_;
// 1B
// 1bit packet_rate_restriction_flag
// 5bits reserved_bits
// The packet_rate_restriction_flag is a 1-bit flag. If the CSPS flag is set to '1', the
// packet_rate_restriction_flag indicates which constraint is applicable to the packet rate, as specified in 2.7.9.
// If the CSPS flag is set to value of '0', then the meaning of the packet_rate_restriction_flag is undefined.
uint8_t packet_rate_restriction_flag_;
// 3B
// 8bits stream_id
// 2bits fixed '11'
// 1bit buffer_bound_scale
// 13bits buffer_size_bound
// Has some audio or video stream, by the next bit is 1.
// Note that we ignore other streams except audio and video.
//
// The stream_id is an 8-bit field that indicates the coding and elementary stream number of the stream to which the
// following P-STD_buffer_bound_scale and P-STD_buffer_size_bound fields refer.
// If stream_id equals '1011 1000' the P-STD_buffer_bound_scale and P-STD_buffer_size_bound fields following the
// stream_id refer to all audio streams in the Program Stream.
// If stream_id equals '1011 1001' the P-STD_buffer_bound_scale and P-STD_buffer_size_bound fields following the
// stream_id refer to all video streams in the Program Stream.
// If the stream_id takes on any other value it shall be a byte value greater than or equal to '1011 1100' and shall
// be interpreted as referring to the stream coding and elementary stream number according to Table 2-18.
//
uint8_t audio_stream_id_;
uint8_t audio_buffer_bound_scale_;
uint16_t audio_buffer_size_bound_;
//
uint8_t video_stream_id_;
uint8_t video_buffer_bound_scale_;
uint16_t video_buffer_size_bound_;
public:
SrsPsPacket(SrsPsContext* context);
virtual ~SrsPsPacket();
public:
virtual srs_error_t decode(SrsBuffer* stream);
private:
virtual srs_error_t decode_pack(SrsBuffer* stream);
virtual srs_error_t decode_system(SrsBuffer* stream);
};
// The Program Stream Map (PSM) provides a description of the elementary streams in the Program Stream and their
// relationship to one another.
// 2.5.4 Program Stream map, hls-mpeg-ts-iso13818-1.pdf, page 77
class SrsPsPsmPacket
{
public:
// 2B
// 1bit current_next_indicator
// 2bits reserved
// 5bits program_stream_map_version
// 7bits reserved
// 1bit marker_bit '1'
// This is a 1-bit field, when set to '1' indicates that the Program Stream Map sent is currently applicable. When
// the bit is set to '0', it indicates that the Program Stream Map sent is not yet applicable and shall be the next
// table to become valid.
uint8_t current_next_indicator_;
// This 5-bit field is the version number of the whole Program Stream Map. The version number shall be incremented
// by 1 modulo 32 whenever the definition of the Program Stream Map changes. When the current_next_indicator is set
// to '1', then the program_stream_map_version shall be that of the currently applicable Program Stream Map. When
// the current_next_indicator is set to '0', then the program_stream_map_version shall be that of the next
// applicable Program Stream Map.
uint8_t program_stream_map_version_;
// 2B + [program_stream_info_length_]B
// The program_stream_info_length is a 16-bit field indicating the total length of the descriptors immediately
// following this field.
uint16_t program_stream_info_length_;
// 2B
// This is a 16-bit field specifying the total length, in bytes, of all elementary stream information in this
// program stream map. It includes the stream_type, elementary_stream_id, and elementary_stream_info_length fields.
uint16_t elementary_stream_map_length_;
// 4B + [elementary_stream_info_length_]B
// 8bits stream_type
// 8bits elementary_stream_id
// 16bits elementary_stream_info_length
// This 8-bit field specifies the type of the stream according to Table 2-29. The stream_type field shall only
// identify elementary streams contained in PES packets. A value of 0x05 is prohibited.
// The elementary_stream_id is an 8-bit field indicating the value of the stream_id field in the PES packet headers
// of PES packets in which this elementary stream is stored.
// The elementary_stream_info_length is a 16-bit field indicating the length in bytes of the descriptors immediately
// following this field.
// Definition for the descriptor() fields may be found in 2.6.
//
uint8_t video_stream_type_;
uint8_t video_elementary_stream_id_;
uint16_t video_elementary_stream_info_length_;
//
uint8_t audio_stream_type_;
uint8_t audio_elementary_stream_id_;
uint16_t audio_elementary_stream_info_length_;
// 4B
// This is a 32-bit field that contains the CRC value that gives a zero output of the registers in the decoder
// defined in Annex A after processing the entire program stream map.
uint32_t CRC_32_;
public:
SrsPsPsmPacket();
virtual ~SrsPsPsmPacket();
public:
virtual srs_error_t decode(SrsBuffer* stream);
};
#endif

View file

@ -68,6 +68,7 @@ SrsTsMessage::SrsTsMessage(SrsTsChannel* c, SrsTsPacket* p)
{
channel = c;
packet = p;
ps_helper_ = NULL;
dts = pts = 0;
sid = (SrsTsPESStreamId)0x00;
@ -108,7 +109,7 @@ srs_error_t SrsTsMessage::dump(SrsBuffer* stream, int* pnb_bytes)
stream->skip(nb_bytes);
}
*pnb_bytes = nb_bytes;
if (pnb_bytes) *pnb_bytes = nb_bytes;
return err;
}
@ -123,7 +124,9 @@ bool SrsTsMessage::completed(int8_t payload_unit_start_indicator)
bool SrsTsMessage::fresh()
{
return payload->length() == 0;
// Note that both must be 0. For PS stream, the payload might be empty but PES_packet_length is not, see
// PsPacketDecodePrivateStream of KernelPSTest. For TS stream, both should be 0 in the same time.
return PES_packet_length == 0 && payload->length() == 0;
}
bool SrsTsMessage::is_audio()
@ -1566,6 +1569,11 @@ srs_error_t SrsMpegPES::decode(SrsBuffer* stream)
// PES_packet_data_byte
// }
// For PS, the PES packet should never be empty, because there is no continuity for PS packet.
if (PES_packet_length <= 0) {
return srs_error_new(ERROR_GB_PS_PSE, "ts: Invalid PES_packet_length=%d for PS", PES_packet_length);
}
// The pos_packet equals to stream pos, so the PES_packet_length is actually the payload length.
nb_payload_ = PES_packet_length;
has_payload_ = true;

View file

@ -219,6 +219,8 @@ public:
// For decoder only, the ts message does not use them, for user to get the channel and packet.
SrsTsChannel* channel;
SrsTsPacket* packet;
// For decoder only, the ts message does not use them, to get the RTP packet source.
void* ps_helper_;
public:
// The audio cache buffer start pts, to flush audio if full.
// @remark the pts is not the adjust one, it's the orignal pts.
@ -228,6 +230,9 @@ public:
bool write_pcr;
// Whether got discontinuity ts, for example, sequence header changed.
bool is_discontinuity;
public:
// The chunk id of TS packet.
uint8_t continuity_counter;
public:
// The timestamp in 90khz
int64_t dts;
@ -237,8 +242,6 @@ public:
SrsTsPESStreamId sid;
// The size of payload, 0 indicates the length() of payload.
uint16_t PES_packet_length;
// The chunk id.
uint8_t continuity_counter;
// The payload bytes.
SrsSimpleStream* payload;
public: