1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-14 12:21:55 +00:00

for #250, decode the PAT of PSI ts packet.

This commit is contained in:
winlin 2015-01-27 16:25:46 +08:00
parent 51aecb8fde
commit 52b62918d9
5 changed files with 394 additions and 9 deletions

View file

@ -486,6 +486,8 @@ Supported operating systems and hardware:
).
1. Support HLS(h.264+mp3) streaming, read
[#301](https://github.com/winlinvip/simple-rtmp-server/issues/301).
1. [dev] Support push MPEG-TS over UDP to SRS, read
[#250](https://github.com/winlinvip/simple-rtmp-server/issues/250).
1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92).
1. [no-plan] Support multiple processes, for both origin and edge

View file

@ -35,19 +35,20 @@ using namespace std;
#include <srs_kernel_ts.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_kernel_ts.hpp>
#include <srs_core_autofree.hpp>
#ifdef SRS_AUTO_STREAM_CASTER
SrsMpegtsOverUdp::SrsMpegtsOverUdp(SrsConfDirective* c)
{
stream = new SrsStream();
context = new SrsTsContext();
output = _srs_config->get_stream_caster_output(c);
}
SrsMpegtsOverUdp::~SrsMpegtsOverUdp()
{
srs_freep(stream);
srs_freep(context);
}
int SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
@ -85,10 +86,7 @@ int SrsMpegtsOverUdp::on_ts_packet(SrsStream* stream)
{
int ret = ERROR_SUCCESS;
SrsTsPacket* packet = new SrsTsPacket();
SrsAutoFree(SrsTsPacket, packet);
if ((ret = packet->decode(stream)) != ERROR_SUCCESS) {
if ((ret = context->decode(stream)) != ERROR_SUCCESS) {
srs_error("mpegts: decode ts packet failed. ret=%d", ret);
return ret;
}

View file

@ -34,6 +34,7 @@ class sockaddr_in;
#include <string>
class SrsStream;
class SrsTsContext;
class SrsConfDirective;
#ifdef SRS_AUTO_STREAM_CASTER
@ -45,6 +46,7 @@ class SrsMpegtsOverUdp
{
private:
SrsStream* stream;
SrsTsContext* context;
std::string output;
public:
SrsMpegtsOverUdp(SrsConfDirective* c);

View file

@ -39,6 +39,7 @@ using namespace std;
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_core_autofree.hpp>
// in ms, for HLS aac sync time.
#define SRS_CONF_DEFAULT_AAC_SYNC 100
@ -401,6 +402,33 @@ SrsMpegtsFrame::SrsMpegtsFrame()
key = false;
}
SrsTsContext::SrsTsContext()
{
}
SrsTsContext::~SrsTsContext()
{
}
int SrsTsContext::decode(SrsStream* stream)
{
int ret = ERROR_SUCCESS;
// parse util EOF of stream.
// for example, parse multiple times for the PES_packet_length(0) packet.
while (!stream->empty()) {
SrsTsPacket* packet = new SrsTsPacket();
SrsAutoFree(SrsTsPacket, packet);
if ((ret = packet->decode(stream)) != ERROR_SUCCESS) {
srs_error("mpegts: decode ts packet failed. ret=%d", ret);
return ret;
}
}
return ret;
}
SrsTsPacket::SrsTsPacket()
{
sync_byte = 0;
@ -412,11 +440,13 @@ SrsTsPacket::SrsTsPacket()
adaption_field_control = SrsTsAdaptationFieldTypeReserved;
continuity_counter = 0;
adaptation_field = NULL;
payload = NULL;
}
SrsTsPacket::~SrsTsPacket()
{
srs_freep(adaptation_field);
srs_freep(payload);
}
int SrsTsPacket::decode(SrsStream* stream)
@ -471,6 +501,23 @@ int SrsTsPacket::decode(SrsStream* stream)
// calc the user defined data size for payload.
int nb_payload = SRS_TS_PACKET_SIZE - (stream->pos() - pos);
// optional: payload.
if (adaption_field_control == SrsTsAdaptationFieldTypePayloadOnly || adaption_field_control == SrsTsAdaptationFieldTypeBoth) {
if (pid == SrsTsPidPAT) {
// 2.4.4.3 Program association Table
srs_freep(payload);
payload = new SrsTsPayloadPAT(this);
} else {
// left bytes as reserved.
stream->skip(nb_payload);
}
if (payload && (ret = payload->decode(stream)) != ERROR_SUCCESS) {
srs_error("ts: demux payload failed. ret=%d", ret);
return ret;
}
}
return ret;
}
@ -713,6 +760,145 @@ int SrsTsAdaptationField::decode(SrsStream* stream)
return ret;
}
SrsTsPayloadPATProgram::SrsTsPayloadPATProgram()
{
number = 0;
pid = 0;
}
SrsTsPayloadPATProgram::~SrsTsPayloadPATProgram()
{
}
SrsTsPayload::SrsTsPayload(SrsTsPacket* p)
{
packet = p;
}
SrsTsPayload::~SrsTsPayload()
{
}
SrsTsPayloadPSI::SrsTsPayloadPSI(SrsTsPacket* p) : SrsTsPayload(p)
{
pointer_field = 0;
}
SrsTsPayloadPSI::~SrsTsPayloadPSI()
{
}
int SrsTsPayloadPSI::decode(SrsStream* stream)
{
int ret = ERROR_SUCCESS;
/**
* When the payload of the Transport Stream packet contains PSI data, the payload_unit_start_indicator has the following
* significance: if the Transport Stream packet carries the first byte of a PSI section, the payload_unit_start_indicator value
* shall be '1', indicating that the first byte of the payload of this Transport Stream packet carries the pointer_field. If the
* Transport Stream packet does not carry the first byte of a PSI section, the payload_unit_start_indicator value shall be '0',
* indicating that there is no pointer_field in the payload. Refer to 2.4.4.1 and 2.4.4.2. This also applies to private streams of
* stream_type 5 (refer to Table 2-29).
*/
if (packet->payload_unit_start_indicator) {
if (!stream->require(1)) {
ret = ERROR_STREAM_CASTER_TS_AF;
srs_error("ts: demux PSI failed. ret=%d", ret);
return ret;
}
pointer_field = stream->read_1bytes();
}
return ret;
}
SrsTsPayloadPAT::SrsTsPayloadPAT(SrsTsPacket* p) : SrsTsPayloadPSI(p)
{
nb_programs = 0;
programs = NULL;
}
SrsTsPayloadPAT::~SrsTsPayloadPAT()
{
srs_freep(programs);
}
int SrsTsPayloadPAT::decode(SrsStream* stream)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsTsPayloadPSI::decode(stream)) != ERROR_SUCCESS) {
return ret;
}
// atleast 8B without programs and crc32
if (!stream->require(8)) {
ret = ERROR_STREAM_CASTER_TS_AF;
srs_error("ts: demux PAT failed. ret=%d", ret);
return ret;
}
// 1B
table_id = (SrsTsPsiId)stream->read_1bytes();
// 2B
section_length = stream->read_2bytes();
section_syntax_indicator = (section_length >> 15) & 0x01;
const0_value = (section_length >> 14) & 0x01;
section_length &= 0x0FFF;
if (!stream->require(section_length)) {
ret = ERROR_STREAM_CASTER_TS_AF;
srs_error("ts: demux PAT section failed. ret=%d", ret);
return ret;
}
int pos = stream->pos();
// 2B
transport_stream_id = stream->read_2bytes();
// 1B
current_next_indicator = stream->read_1bytes();
version_number = (current_next_indicator >> 1) & 0x1F;
current_next_indicator &= 0x01;
// TODO: FIXME: check the indicator.
// 1B
section_number = stream->read_1bytes();
// 1B
last_section_number = stream->read_1bytes();
// multiple 4B program data.
int program_bytes = section_length - 4 - (stream->pos() - pos);
nb_programs = program_bytes / 4;
if (nb_programs > 0) {
srs_freep(programs);
programs = new SrsTsPayloadPATProgram[nb_programs];
for (int i = 0; i < nb_programs; i++) {
SrsTsPayloadPATProgram* program = programs + i;
int tmpv = stream->read_4bytes();
program->number = (int16_t)((tmpv >> 16) & 0xFFFF);
program->pid = (int16_t)(tmpv & 0x1FFF);
}
}
// 4B
if (!stream->require(4)) {
ret = ERROR_STREAM_CASTER_TS_AF;
srs_error("ts: demux PAT crc32 failed. ret=%d", ret);
return ret;
}
CRC_32 = stream->read_4bytes();
// TODO: FIXME: verfy crc32.
return ret;
}
SrsTSMuxer::SrsTSMuxer(SrsFileWriter* w)
{
writer = w;

View file

@ -42,6 +42,7 @@ class SrsAvcAacCodec;
class SrsCodecSample;
class SrsSimpleBuffer;
class SrsTsAdaptationField;
class SrsTsPayload;
// Transport Stream packets are 188 bytes in length.
#define SRS_TS_PACKET_SIZE 188
@ -108,6 +109,22 @@ enum SrsTsAdaptationFieldType
SrsTsAdaptationFieldTypeBoth = 0x03,
};
/**
* the context of ts, to decode the ts stream.
*/
class SrsTsContext
{
public:
SrsTsContext();
virtual ~SrsTsContext();
public:
/**
* the stream contains only one ts packet.
* @remark we will consume all bytes in stream.
*/
virtual int decode(SrsStream* stream);
};
/**
* the packet in ts stream,
* 2.4.3.2 Transport Stream packet layer, hls-mpeg-ts-iso13818-1.pdf, page 36
@ -203,14 +220,11 @@ public:
u_int8_t continuity_counter; //4bits
private:
SrsTsAdaptationField* adaptation_field;
SrsTsPayload* payload;
public:
SrsTsPacket();
virtual ~SrsTsPacket();
public:
/**
* the stream contains only one ts packet.
* @remark we will consume all bytes in stream.
*/
virtual int decode(SrsStream* stream);
};
@ -515,6 +529,189 @@ public:
virtual int decode(SrsStream* stream);
};
/**
* 2.4.4.4 Table_id assignments, hls-mpeg-ts-iso13818-1.pdf, page 62
* The table_id field identifies the contents of a Transport Stream PSI section as shown in Table 2-26.
*/
enum SrsTsPsiId
{
// program_association_section
SrsTsPsiIdPas = 0x00,
// conditional_access_section (CA_section)
SrsTsPsiIdCas = 0x01,
// TS_program_map_section
SrsTsPsiIdPms = 0x02,
// TS_description_section
SrsTsPsiIdDs = 0x03,
// ISO_IEC_14496_scene_description_section
SrsTsPsiIdSds = 0x04,
// ISO_IEC_14496_object_descriptor_section
SrsTsPsiIdOds = 0x05,
// ITU-T Rec. H.222.0 | ISO/IEC 13818-1 reserved
SrsTsPsiIdIso138181Start = 0x06,
SrsTsPsiIdIso138181End = 0x37,
// Defined in ISO/IEC 13818-6
SrsTsPsiIdIso138186Start = 0x38,
SrsTsPsiIdIso138186End = 0x3F,
// User private
SrsTsPsiIdUserStart = 0x40,
SrsTsPsiIdUserEnd = 0xFE,
// forbidden
SrsTsPsiIdForbidden = 0xFF,
};
/**
* the program of PAT of PSI ts packet.
*/
class SrsTsPayloadPATProgram
{
public:
// 4B
/**
* Program_number is a 16-bit field. It specifies the program to which the program_map_PID is
* applicable. When set to 0x0000, then the following PID reference shall be the network PID. For all other cases the value
* of this field is user defined. This field shall not take any single value more than once within one version of the Program
* Association Table.
*/
int16_t number; // 16bits
// reserved 3bits
/**
* program_map_PID/network_PID 13bits
* network_PID ¨C The network_PID is a 13-bit field, which is used only in conjunction with the value of the
* program_number set to 0x0000, specifies the PID of the Transport Stream packets which shall contain the Network
* Information Table. The value of the network_PID field is defined by the user, but shall only take values as specified in
* Table 2-3. The presence of the network_PID is optional.
*/
int16_t pid;
public:
SrsTsPayloadPATProgram();
virtual ~SrsTsPayloadPATProgram();
};
/**
* the payload of ts packet, can be PES or PSI payload.
*/
class SrsTsPayload
{
protected:
SrsTsPacket* packet;
public:
SrsTsPayload(SrsTsPacket* p);
virtual ~SrsTsPayload();
public:
virtual int decode(SrsStream* stream) = 0;
};
/**
* the PSI payload of ts packet.
* 2.4.4 Program specific information, hls-mpeg-ts-iso13818-1.pdf, page 59
*/
class SrsTsPayloadPSI : public SrsTsPayload
{
public:
// 1B
/**
* This is an 8-bit field whose value shall be the number of bytes, immediately following the pointer_field
* until the first byte of the first section that is present in the payload of the Transport Stream packet (so a value of 0x00 in
* the pointer_field indicates that the section starts immediately after the pointer_field). When at least one section begins in
* a given Transport Stream packet, then the payload_unit_start_indicator (refer to 2.4.3.2) shall be set to 1 and the first
* byte of the payload of that Transport Stream packet shall contain the pointer. When no section begins in a given
* Transport Stream packet, then the payload_unit_start_indicator shall be set to 0 and no pointer shall be sent in the
* payload of that packet.
*/
int8_t pointer_field;
public:
SrsTsPayloadPSI(SrsTsPacket* p);
virtual ~SrsTsPayloadPSI();
public:
virtual int decode(SrsStream* stream);
};
/**
* the PAT payload of PSI ts packet.
* 2.4.4.3 Program association Table, hls-mpeg-ts-iso13818-1.pdf, page 61
* The Program Association Table provides the correspondence between a program_number and the PID value of the
* Transport Stream packets which carry the program definition. The program_number is the numeric label associated with
* a program.
*/
class SrsTsPayloadPAT : public SrsTsPayloadPSI
{
public:
// 1B
/**
* This is an 8-bit field, which shall be set to 0x00 as shown in Table 2-26.
*/
SrsTsPsiId table_id; //8bits
// 2B
/**
* The section_syntax_indicator is a 1-bit field which shall be set to '1'.
*/
int8_t section_syntax_indicator; //1bit
/**
* const value, must be '0'
*/
int8_t const0_value; //1bit
// 2bits reserved.
/**
* This is a 12-bit field, the first two bits of which shall be '00'. The remaining 10 bits specify the number
* of bytes of the section, starting immediately following the section_length field, and including the CRC. The value in this
* field shall not exceed 1021 (0x3FD).
*/
u_int16_t section_length; //12bits
// 2B
/**
* This is a 16-bit field which serves as a label to identify this Transport Stream from any other
* multiplex within a network. Its value is defined by the user.
*/
u_int16_t transport_stream_id; //16bits
// 1B
// 2bits reerverd.
/**
* This 5-bit field is the version number of the whole Program Association Table. The version number
* shall be incremented by 1 modulo 32 whenever the definition of the Program Association Table changes. When the
* current_next_indicator is set to '1', then the version_number shall be that of the currently applicable Program Association
* Table. When the current_next_indicator is set to '0', then the version_number shall be that of the next applicable Program
* Association Table.
*/
int8_t version_number; //5bits
/**
* A 1-bit indicator, which when set to '1' indicates that the Program Association Table sent is
* currently applicable. When the bit is set to '0', it indicates that the table sent is not yet applicable and shall be the next
* table to become valid.
*/
int8_t current_next_indicator; //1bit
// 1B
/**
* This 8-bit field gives the number of this section. The section_number of the first section in the
* Program Association Table shall be 0x00. It shall be incremented by 1 with each additional section in the Program
* Association Table.
*/
u_int8_t section_number; //8bits
// 1B
/**
* This 8-bit field specifies the number of the last section (that is, the section with the highest
* section_number) of the complete Program Association Table.
*/
u_int8_t last_section_number; //8bits
// multiple 4B program data.
int nb_programs;
SrsTsPayloadPATProgram* programs;
// 4B
int32_t CRC_32; //32bits
public:
SrsTsPayloadPAT(SrsTsPacket* p);
virtual ~SrsTsPayloadPAT();
public:
virtual int decode(SrsStream* stream);
};
/**
* write data from frame(header info) and buffer(data) to ts file.
* it's a simple object wrapper for utility from nginx-rtmp: SrsMpegtsWriter