mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
update the ts_info parse the PMT and PES header
This commit is contained in:
parent
89332789d1
commit
a47a53f271
3 changed files with 1077 additions and 648 deletions
|
@ -1,5 +1,5 @@
|
||||||
# the listen ports, split by space.
|
# the listen ports, split by space.
|
||||||
listen 1937;
|
listen 1935;
|
||||||
# the default chunk size is 128, max is 65536,
|
# the default chunk size is 128, max is 65536,
|
||||||
# some client does not support chunk size change,
|
# some client does not support chunk size change,
|
||||||
# however, most clients supports it and it can improve
|
# however, most clients supports it and it can improve
|
||||||
|
|
|
@ -10,6 +10,8 @@ g++ -o ts_info ts_info.cpp -g -O0 -ansi
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define trace(msg, ...) printf(msg"\n", ##__VA_ARGS__);
|
#define trace(msg, ...) printf(msg"\n", ##__VA_ARGS__);
|
||||||
#define srs_freep(p) delete p; p = NULL
|
#define srs_freep(p) delete p; p = NULL
|
||||||
#define srs_freepa(p) delete[] p; p = NULL
|
#define srs_freepa(p) delete[] p; p = NULL
|
||||||
|
@ -63,11 +65,65 @@ Annex A
|
||||||
#define AFC_BOTH 0x03
|
#define AFC_BOTH 0x03
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct TSPacket
|
// Table 2-29 – Stream type assignments. page 66.
|
||||||
|
enum TSStreamType
|
||||||
{
|
{
|
||||||
// 4B ts packet header.
|
/*defined by ffmpeg*/
|
||||||
struct Header
|
TSStreamTypeVideoMpeg1 = 0x01,
|
||||||
{
|
TSStreamTypeVideoMpeg2 = 0x02,
|
||||||
|
TSStreamTypeAudioMpeg1 = 0x03,
|
||||||
|
TSStreamTypeAudioMpeg2 = 0x04,
|
||||||
|
TSStreamTypePrivateSection = 0x05,
|
||||||
|
TSStreamTypePrivateData = 0x06,
|
||||||
|
TSStreamTypeAudioAAC = 0x0f,
|
||||||
|
TSStreamTypeVideoMpeg4 = 0x10,
|
||||||
|
TSStreamTypeVideoH264 = 0x1b,
|
||||||
|
TSStreamTypeAudioAC3 = 0x81,
|
||||||
|
TSStreamTypeAudioDTS = 0x8a,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the actually parsed type.
|
||||||
|
*/
|
||||||
|
enum TSPidType
|
||||||
|
{
|
||||||
|
TSPidTypeReserved = 0, // TSPidTypeReserved, nothing parsed, used reserved.
|
||||||
|
|
||||||
|
TSPidTypePAT, // Program associtate table
|
||||||
|
TSPidTypePMT, // Program map table.
|
||||||
|
|
||||||
|
TSPidTypeVideo,
|
||||||
|
TSPidTypeAudio,
|
||||||
|
};
|
||||||
|
|
||||||
|
// forward declares.
|
||||||
|
class TSHeader;
|
||||||
|
class TSAdaptionField;
|
||||||
|
class TSPayload;
|
||||||
|
class TSPayloadReserved;
|
||||||
|
class TSPayloadPAT;
|
||||||
|
class TSPayloadPMT;
|
||||||
|
class TSPayloadPES;
|
||||||
|
class TSContext;
|
||||||
|
|
||||||
|
// TSPacket declares.
|
||||||
|
class TSPacket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TSHeader* header;
|
||||||
|
TSAdaptionField* adaption_field;
|
||||||
|
TSPayload* payload;
|
||||||
|
|
||||||
|
TSPacket();
|
||||||
|
virtual ~TSPacket();
|
||||||
|
int demux(TSContext* ctx, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
int finish();
|
||||||
|
};
|
||||||
|
|
||||||
|
// TSHeader declares.
|
||||||
|
class TSHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
// 1B
|
// 1B
|
||||||
int8_t sync_byte; //8bits
|
int8_t sync_byte; //8bits
|
||||||
// 2B
|
// 2B
|
||||||
|
@ -80,48 +136,16 @@ struct TSPacket
|
||||||
int8_t adaption_field_control; //2bits
|
int8_t adaption_field_control; //2bits
|
||||||
u_int8_t continuity_counter; //4bits
|
u_int8_t continuity_counter; //4bits
|
||||||
|
|
||||||
int get_size()
|
TSHeader();
|
||||||
{
|
virtual ~TSHeader();
|
||||||
return 4;
|
int get_size();
|
||||||
}
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
// variant ts packet adation field. page 40.
|
||||||
{
|
class TSAdaptionField
|
||||||
int ret = 0;
|
{
|
||||||
|
public:
|
||||||
// ts packet header.
|
|
||||||
sync_byte = *p++;
|
|
||||||
if (sync_byte != 0x47) {
|
|
||||||
trace("ts+sync_bytes invalid sync_bytes: %#x, expect is 0x47", sync_byte);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = 0;
|
|
||||||
((char*)&pid)[1] = *p++;
|
|
||||||
((char*)&pid)[0] = *p++;
|
|
||||||
|
|
||||||
transport_error_indicator = (pid >> 15) & 0x01;
|
|
||||||
payload_unit_start_indicator = (pid >> 14) & 0x01;
|
|
||||||
transport_priority = (pid >> 13) & 0x01;
|
|
||||||
pid &= 0x1FFF;
|
|
||||||
|
|
||||||
continuity_counter = *p++;
|
|
||||||
|
|
||||||
transport_scrambling_control = (continuity_counter >> 6) & 0x03;
|
|
||||||
adaption_field_control = (continuity_counter >> 4) & 0x03;
|
|
||||||
continuity_counter &= 0x0F;
|
|
||||||
|
|
||||||
trace("ts+header sync: %#x error: %d unit_start: %d priotiry: %d pid: %d scrambling: %d adaption: %d counter: %d",
|
|
||||||
sync_byte, transport_error_indicator, payload_unit_start_indicator, transport_priority, pid,
|
|
||||||
transport_scrambling_control, adaption_field_control, continuity_counter);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} *header;
|
|
||||||
|
|
||||||
// variant ts packet adation field.
|
|
||||||
struct AdaptionField
|
|
||||||
{
|
|
||||||
// 1B
|
// 1B
|
||||||
u_int8_t adaption_field_length; //8bits
|
u_int8_t adaption_field_length; //8bits
|
||||||
// 1B
|
// 1B
|
||||||
|
@ -180,29 +204,288 @@ struct TSPacket
|
||||||
// user defined data size.
|
// user defined data size.
|
||||||
int __user_size;
|
int __user_size;
|
||||||
|
|
||||||
AdaptionField()
|
TSAdaptionField();
|
||||||
{
|
virtual ~TSAdaptionField();
|
||||||
|
int get_size();
|
||||||
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
|
// variant ts packet payload.
|
||||||
|
// PES packet or PSI table.
|
||||||
|
// TSPayloadPAT: page 61.
|
||||||
|
class TSPayload
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* the size of payload(payload plush the 1byte pointer_field).
|
||||||
|
*/
|
||||||
|
int size;
|
||||||
|
int pointer_field_size;
|
||||||
|
|
||||||
|
TSPidType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.4.4.2 Semantics definition of fields in pointer syntax
|
||||||
|
*/
|
||||||
|
u_int8_t pointer_field;
|
||||||
|
|
||||||
|
TSPayloadReserved* reserved;
|
||||||
|
TSPayloadPAT* pat;
|
||||||
|
TSPayloadPMT* pmt;
|
||||||
|
TSPayloadPES* pes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.4.3.6 PES packet. page 49.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TSPayload();
|
||||||
|
virtual ~TSPayload();;
|
||||||
|
void read_pointer_field(TSPacket* pkt, u_int8_t*& p);
|
||||||
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.4.4.3 Program association Table. page 61.
|
||||||
|
*/
|
||||||
|
class TSPayloadPAT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 1B
|
||||||
|
u_int8_t table_id; //8bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
int8_t section_syntax_indicator; //1bit
|
||||||
|
int8_t const0_value; //1bit
|
||||||
|
// 2bits reserved.
|
||||||
|
u_int16_t section_length; //12bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
u_int16_t transport_stream_id; //16bits
|
||||||
|
|
||||||
|
// 1B
|
||||||
|
// 2bits reerverd.
|
||||||
|
int8_t version_number; //5bits
|
||||||
|
int8_t current_next_indicator; //1bit
|
||||||
|
|
||||||
|
// 1B
|
||||||
|
u_int8_t section_number; //8bits
|
||||||
|
|
||||||
|
// 1B
|
||||||
|
u_int8_t last_section_number; //8bits
|
||||||
|
|
||||||
|
// multiple 4B program data.
|
||||||
|
// program_number 16bits
|
||||||
|
// reserved 2bits
|
||||||
|
// 13bits data: 0x1FFF
|
||||||
|
// if program_number program_map_PID 13bits
|
||||||
|
// else network_PID 13bytes.
|
||||||
|
int program_size;
|
||||||
|
int32_t* programs; //32bits
|
||||||
|
|
||||||
|
// 4B
|
||||||
|
int32_t CRC_32; //32bits
|
||||||
|
|
||||||
|
TSPayloadPAT();
|
||||||
|
virtual ~TSPayloadPAT();
|
||||||
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TSPMTESInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 1B
|
||||||
|
u_int8_t stream_type; //8bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
// 3bits reserved
|
||||||
|
int16_t elementary_PID; //13bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
// 4bits reserved
|
||||||
|
int16_t ES_info_length; //12bits
|
||||||
|
|
||||||
|
char* ES_info; //[ES_info_length] bytes.
|
||||||
|
|
||||||
|
TSPMTESInfo();
|
||||||
|
virtual ~TSPMTESInfo();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.4.4.8 Program Map Table. page 64.
|
||||||
|
*/
|
||||||
|
class TSPayloadPMT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 1B
|
||||||
|
u_int8_t table_id; //8bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
int8_t section_syntax_indicator; //1bit
|
||||||
|
int8_t const0_value; //1bit
|
||||||
|
// 2bits reserved.
|
||||||
|
u_int16_t section_length; //12bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
u_int16_t program_number; //16bits
|
||||||
|
|
||||||
|
// 1B
|
||||||
|
// 2bits reerverd.
|
||||||
|
int8_t version_number; //5bits
|
||||||
|
int8_t current_next_indicator; //1bit
|
||||||
|
|
||||||
|
// 1B
|
||||||
|
u_int8_t section_number; //8bits
|
||||||
|
|
||||||
|
// 1B
|
||||||
|
u_int8_t last_section_number; //8bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
// 2bits reserved.
|
||||||
|
int16_t PCR_PID; //16bits
|
||||||
|
|
||||||
|
// 2B
|
||||||
|
// 4bits reserved.
|
||||||
|
int16_t program_info_length; //12bits
|
||||||
|
char* program_info_desc; //[program_info_length]bytes
|
||||||
|
|
||||||
|
// array of TSPMTESInfo.
|
||||||
|
std::vector<TSPMTESInfo*> ES_info;
|
||||||
|
|
||||||
|
// 4B
|
||||||
|
int32_t CRC_32; //32bits
|
||||||
|
|
||||||
|
TSPayloadPMT();
|
||||||
|
virtual ~TSPayloadPMT();
|
||||||
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.4.3.7 Semantic definition of fields in PES packet. page 49.
|
||||||
|
*/
|
||||||
|
class TSPayloadPES
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 3B
|
||||||
|
int32_t packet_start_code_prefix; //24bits
|
||||||
|
// 1B
|
||||||
|
u_int8_t stream_id; //8bits
|
||||||
|
// 2B
|
||||||
|
u_int16_t PES_packet_length; //16bits
|
||||||
|
|
||||||
|
TSPayloadPES();
|
||||||
|
virtual ~TSPayloadPES();
|
||||||
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TSPayloadReserved
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int size;
|
||||||
|
char* bytes;
|
||||||
|
|
||||||
|
TSPayloadReserved();
|
||||||
|
virtual ~TSPayloadReserved();
|
||||||
|
int demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TSPid
|
||||||
|
{
|
||||||
|
TSPidType type;
|
||||||
|
int16_t pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ts context
|
||||||
|
class TSContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* consumed pids.
|
||||||
|
*/
|
||||||
|
int pid_size;
|
||||||
|
TSPid* pids;
|
||||||
|
|
||||||
|
TSContext();
|
||||||
|
virtual ~TSContext();
|
||||||
|
bool exists(int16_t pid);
|
||||||
|
TSPid* get(int16_t pid);
|
||||||
|
void push(TSPidType type, int16_t pid);
|
||||||
|
};
|
||||||
|
|
||||||
|
TSContext::TSContext()
|
||||||
|
{
|
||||||
|
pid_size = 0;
|
||||||
|
pids = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSContext::~TSContext()
|
||||||
|
{
|
||||||
|
srs_freepa(pids);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TSContext::exists(int16_t pid)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < pid_size; i++) {
|
||||||
|
if (pid == pids[i].pid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPid* TSContext::get(int16_t pid)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < pid_size; i++) {
|
||||||
|
if (pid == pids[i].pid) {
|
||||||
|
return &pids[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TSContext::push(TSPidType type, int16_t pid)
|
||||||
|
{
|
||||||
|
if (exists(pid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPid* p = new TSPid[pid_size + 1];
|
||||||
|
memcpy(p, pids, sizeof(TSPid) * pid_size);
|
||||||
|
|
||||||
|
p[pid_size] = (TSPid){type, pid};
|
||||||
|
pid_size++;
|
||||||
|
|
||||||
|
srs_freepa(pids);
|
||||||
|
pids = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSAdaptionField::TSAdaptionField()
|
||||||
|
{
|
||||||
transport_private_data = NULL;
|
transport_private_data = NULL;
|
||||||
af_ext_reserved = NULL;
|
af_ext_reserved = NULL;
|
||||||
af_reserved = NULL;
|
af_reserved = NULL;
|
||||||
|
|
||||||
__user_size = 0;
|
__user_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AdaptionField()
|
TSAdaptionField::~TSAdaptionField()
|
||||||
{
|
{
|
||||||
srs_freepa(transport_private_data);
|
srs_freepa(transport_private_data);
|
||||||
srs_freepa(af_ext_reserved);
|
srs_freepa(af_ext_reserved);
|
||||||
srs_freepa(af_reserved);
|
srs_freepa(af_reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_size()
|
int TSAdaptionField::get_size()
|
||||||
{
|
{
|
||||||
return __user_size;
|
return __user_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
int TSAdaptionField::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
adaption_field_length = *p++;
|
adaption_field_length = *p++;
|
||||||
|
@ -333,58 +616,24 @@ struct TSPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} *adaption_field;
|
|
||||||
|
|
||||||
// variant ts packet payload.
|
TSPayloadReserved::TSPayloadReserved()
|
||||||
// PES packet or PSI table.
|
{
|
||||||
struct Payload
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* the size of payload(payload plush the 1byte pointer_field).
|
|
||||||
*/
|
|
||||||
int size;
|
|
||||||
int pointer_field_size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the actually parsed type.
|
|
||||||
*/
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
TypeUnknown=-1,
|
|
||||||
TypeReserved, // TypeReserved, nothing parsed, used reserved.
|
|
||||||
TypePAT, //TypePAT, PAT parsed, in pat field.
|
|
||||||
} type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 2.4.4.2 Semantics definition of fields in pointer syntax
|
|
||||||
*/
|
|
||||||
u_int8_t pointer_field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* if not parsed, store data in this field.
|
|
||||||
*/
|
|
||||||
struct Reserved
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
char* bytes;
|
|
||||||
|
|
||||||
Reserved()
|
|
||||||
{
|
|
||||||
size = 0;
|
size = 0;
|
||||||
bytes = NULL;
|
bytes = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Reserved()
|
TSPayloadReserved::~TSPayloadReserved()
|
||||||
{
|
{
|
||||||
srs_freepa(bytes);
|
srs_freepa(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
int TSPayloadReserved::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
size = ppkt->payload->size - ppkt->payload->pointer_field_size;
|
size = pkt->payload->size - pkt->payload->pointer_field_size;
|
||||||
|
|
||||||
// not parsed bytes.
|
// not parsed bytes.
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
|
@ -394,66 +643,20 @@ struct TSPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} *reserved;
|
|
||||||
|
|
||||||
/**
|
TSPayloadPAT::TSPayloadPAT()
|
||||||
* 2.4.4.3 Program association Table. page 61.
|
{
|
||||||
*/
|
|
||||||
struct PAT {
|
|
||||||
// 1B
|
|
||||||
u_int8_t table_id; //8bits
|
|
||||||
|
|
||||||
// 2B
|
|
||||||
int8_t section_syntax_indicator; //1bit
|
|
||||||
int8_t const0_value; //1bit
|
|
||||||
// 2bits reserved.
|
|
||||||
u_int16_t section_length; //12bits
|
|
||||||
|
|
||||||
// 2B
|
|
||||||
u_int16_t transport_stream_id; //16bits
|
|
||||||
|
|
||||||
// 1B
|
|
||||||
// 2bits reerverd.
|
|
||||||
int8_t version_number; //5bits
|
|
||||||
int8_t current_next_indicator; //1bit
|
|
||||||
|
|
||||||
// 1B
|
|
||||||
u_int8_t section_number; //8bits
|
|
||||||
|
|
||||||
// 1B
|
|
||||||
u_int8_t last_section_number; //8bits
|
|
||||||
|
|
||||||
// multiple 4B program data.
|
|
||||||
// program_number 16bits
|
|
||||||
// reserved 2bits
|
|
||||||
// 13bits data: 0x1FFF
|
|
||||||
// if program_number program_map_PID 13bits
|
|
||||||
// else network_PID 13bytes.
|
|
||||||
int program_size;
|
|
||||||
int32_t* programs; //32bits
|
|
||||||
|
|
||||||
// 4B
|
|
||||||
int32_t CRC_32; //32bits
|
|
||||||
|
|
||||||
PAT()
|
|
||||||
{
|
|
||||||
programs = NULL;
|
programs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~PAT()
|
TSPayloadPAT::~TSPayloadPAT()
|
||||||
{
|
{
|
||||||
srs_freepa(programs);
|
srs_freepa(programs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_program(int index)
|
int TSPayloadPAT::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
{
|
{
|
||||||
srs_assert(index < program_size);
|
|
||||||
return programs[index] & 0x1FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
table_id = *p++;
|
table_id = *p++;
|
||||||
|
@ -489,6 +692,9 @@ struct TSPacket
|
||||||
pp[2] = *p++;
|
pp[2] = *p++;
|
||||||
pp[1] = *p++;
|
pp[1] = *p++;
|
||||||
pp[0] = *p++;
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
int16_t pid = programs[i] & 0x1FFF;
|
||||||
|
ctx->push(TSPidTypePMT, pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,79 +705,251 @@ struct TSPacket
|
||||||
pp[0] = *p++;
|
pp[0] = *p++;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPMTESInfo::TSPMTESInfo()
|
||||||
|
{
|
||||||
|
ES_info_length = 0;
|
||||||
|
ES_info = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPMTESInfo::~TSPMTESInfo()
|
||||||
|
{
|
||||||
|
srs_freepa(ES_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPayloadPMT::TSPayloadPMT()
|
||||||
|
{
|
||||||
|
program_info_length = 0;
|
||||||
|
program_info_desc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPayloadPMT::~TSPayloadPMT()
|
||||||
|
{
|
||||||
|
srs_freepa(program_info_desc);
|
||||||
|
|
||||||
|
for (std::vector<TSPMTESInfo*>::iterator it = ES_info.begin(); it != ES_info.end(); ++it) {
|
||||||
|
TSPMTESInfo* info = *it;
|
||||||
|
srs_freep(info);
|
||||||
}
|
}
|
||||||
} *pat;
|
ES_info.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
int TSPayloadPMT::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
* 2.4.3.6 PES packet. page 49.
|
{
|
||||||
*/
|
int ret = 0;
|
||||||
|
|
||||||
Payload()
|
table_id = *p++;
|
||||||
{
|
|
||||||
|
char* pp = (char*)§ion_length;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
u_int8_t* pos = p;
|
||||||
|
|
||||||
|
section_syntax_indicator = (section_length >> 15) & 0x01;
|
||||||
|
const0_value = (section_length >> 14) & 0x01;
|
||||||
|
section_length &= 0x0FFF;
|
||||||
|
|
||||||
|
pp = (char*)&program_number;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
current_next_indicator = *p++;
|
||||||
|
version_number = (current_next_indicator >> 1) & 0x1F;
|
||||||
|
current_next_indicator &= 0x01;
|
||||||
|
|
||||||
|
section_number = *p++;
|
||||||
|
last_section_number = *p++;
|
||||||
|
|
||||||
|
pp = (char*)&PCR_PID;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
PCR_PID &= 0x1FFF;
|
||||||
|
|
||||||
|
pp = (char*)&program_info_length;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
program_info_length &= 0xFFF;
|
||||||
|
|
||||||
|
if (program_info_length > 0) {
|
||||||
|
program_info_desc = new char[program_info_length];
|
||||||
|
memcpy(program_info_desc, p, program_info_length);
|
||||||
|
p += program_info_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [section_length] - 4(CRC) - 9B - [program_info_length]
|
||||||
|
int ES_bytes = section_length - 4 - 9 - program_info_length;
|
||||||
|
while (ES_bytes > 0) {
|
||||||
|
TSPMTESInfo* info = new TSPMTESInfo();
|
||||||
|
|
||||||
|
info->stream_type = *p++;
|
||||||
|
ES_bytes--;
|
||||||
|
|
||||||
|
pp = (char*)&info->elementary_PID;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
ES_bytes -= 2;
|
||||||
|
|
||||||
|
info->elementary_PID &= 0x1FFF;
|
||||||
|
|
||||||
|
pp = (char*)&info->ES_info_length;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
ES_bytes -= 2;
|
||||||
|
|
||||||
|
info->ES_info_length &= 0x0FFF;
|
||||||
|
|
||||||
|
if (info->ES_info_length > 0) {
|
||||||
|
info->ES_info = new char[info->ES_info_length];
|
||||||
|
memcpy(info->ES_info, p, info->ES_info_length);
|
||||||
|
|
||||||
|
p += info->ES_info_length;
|
||||||
|
ES_bytes -= info->ES_info_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ES_info.push_back(info);
|
||||||
|
|
||||||
|
// TODO: support more video type.
|
||||||
|
if (info->stream_type == TSStreamTypeVideoH264) {
|
||||||
|
ctx->push(TSPidTypeVideo, info->elementary_PID);
|
||||||
|
}
|
||||||
|
// TODO: support more audio type.
|
||||||
|
if (info->stream_type == TSStreamTypeAudioAAC) {
|
||||||
|
ctx->push(TSPidTypeAudio, info->elementary_PID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pp = (char*)&CRC_32;
|
||||||
|
pp[3] = *p++;
|
||||||
|
pp[2] = *p++;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPayloadPES::TSPayloadPES()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPayloadPES::~TSPayloadPES()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TSPayloadPES::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
char* pp = (char*)&packet_start_code_prefix;
|
||||||
|
pp[2] = *p++;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
packet_start_code_prefix &= 0xFFFFFF;
|
||||||
|
|
||||||
|
stream_id = *p++;
|
||||||
|
|
||||||
|
pp = (char*)&PES_packet_length;
|
||||||
|
pp[1] = *p++;
|
||||||
|
pp[0] = *p++;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.4.3.6 PES packet. page 49.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TSPayload::TSPayload()
|
||||||
|
{
|
||||||
size = 0;
|
size = 0;
|
||||||
pointer_field_size = 0;
|
pointer_field_size = 0;
|
||||||
|
|
||||||
type = TypeUnknown;
|
type = TSPidTypeReserved;
|
||||||
reserved = NULL;
|
reserved = NULL;
|
||||||
pat = NULL;
|
pat = NULL;
|
||||||
}
|
pmt = NULL;
|
||||||
|
pes = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~Payload()
|
TSPayload::~TSPayload()
|
||||||
{
|
{
|
||||||
srs_freep(reserved);
|
srs_freep(reserved);
|
||||||
srs_freep(pat);
|
srs_freep(pat);
|
||||||
}
|
srs_freep(pmt);
|
||||||
|
srs_freep(pes);
|
||||||
|
}
|
||||||
|
|
||||||
int demux(TSPacket* ppkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
void TSPayload::read_pointer_field(TSPacket* pkt, u_int8_t*& p)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
if (pkt->header->payload_unit_start_indicator) {
|
||||||
|
|
||||||
if (ppkt->header->payload_unit_start_indicator) {
|
|
||||||
pointer_field = *p++;
|
pointer_field = *p++;
|
||||||
pointer_field_size = 1;
|
pointer_field_size = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ppkt->header->pid == PID_PAT) {
|
int TSPayload::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
type = TypePAT;
|
{
|
||||||
pat = new PAT();
|
int ret = 0;
|
||||||
return pat->demux(ppkt, start, last, p);
|
|
||||||
|
if (pkt->header->pid == PID_PAT) {
|
||||||
|
read_pointer_field(pkt, p);
|
||||||
|
|
||||||
|
type = TSPidTypePAT;
|
||||||
|
pat = new TSPayloadPAT();
|
||||||
|
return pat->demux(ctx, pkt, start, last, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSPid* pid = ctx->get(pkt->header->pid);
|
||||||
|
if (pid && pid->type == TSPidTypePMT) {
|
||||||
|
read_pointer_field(pkt, p);
|
||||||
|
|
||||||
|
type = pid->type;
|
||||||
|
pmt = new TSPayloadPMT();
|
||||||
|
return pmt->demux(ctx, pkt, start, last, p);
|
||||||
|
}
|
||||||
|
if (pid && (pid->type == TSPidTypeVideo || pid->type == TSPidTypeAudio)) {
|
||||||
|
type = pid->type;
|
||||||
|
pes = new TSPayloadPES();
|
||||||
|
return pes->demux(ctx, pkt, start, last, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// not parsed bytes.
|
// not parsed bytes.
|
||||||
type = TypeReserved;
|
type = TSPidTypeReserved;
|
||||||
reserved = new Reserved();
|
reserved = new TSPayloadReserved();
|
||||||
if ((ret = reserved->demux(ppkt, start, last, p)) != 0) {
|
if ((ret = reserved->demux(ctx, pkt, start, last, p)) != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} *payload;
|
|
||||||
|
|
||||||
TSPacket()
|
TSPacket::TSPacket()
|
||||||
{
|
{
|
||||||
header = new Header();
|
header = new TSHeader();
|
||||||
adaption_field = new AdaptionField();
|
adaption_field = new TSAdaptionField();
|
||||||
payload = new Payload();
|
payload = new TSPayload();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TSPacket()
|
TSPacket::~TSPacket()
|
||||||
{
|
{
|
||||||
srs_freep(header);
|
srs_freep(header);
|
||||||
srs_freep(adaption_field);
|
srs_freep(adaption_field);
|
||||||
srs_freep(payload);
|
srs_freep(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
int demux(u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
int TSPacket::demux(TSContext* ctx, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if ((ret = header->demux(this, start, last, p)) != 0) {
|
if ((ret = header->demux(ctx, this, start, last, p)) != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header->adaption_field_control == AFC_ADAPTION_ONLY || header->adaption_field_control == AFC_BOTH) {
|
if (header->adaption_field_control == AFC_ADAPTION_ONLY || header->adaption_field_control == AFC_BOTH) {
|
||||||
if ((ret = adaption_field->demux(this, start, last, p)) != 0) {
|
if ((ret = adaption_field->demux(ctx, this, start, last, p)) != 0) {
|
||||||
trace("ts+header af(adaption field) decode error. ret=%d", ret);
|
trace("ts+header af(adaption field) decode error. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -582,7 +960,7 @@ struct TSPacket
|
||||||
payload->size = TS_PACKET_SIZE - header->get_size() - adaption_field->get_size();
|
payload->size = TS_PACKET_SIZE - header->get_size() - adaption_field->get_size();
|
||||||
|
|
||||||
if (header->adaption_field_control == AFC_PAYLOAD_ONLY || header->adaption_field_control == AFC_BOTH) {
|
if (header->adaption_field_control == AFC_PAYLOAD_ONLY || header->adaption_field_control == AFC_BOTH) {
|
||||||
if ((ret = payload->demux(this, start, last, p)) != 0) {
|
if ((ret = payload->demux(ctx, this, start, last, p)) != 0) {
|
||||||
trace("ts+header payload decode error. ret=%d", ret);
|
trace("ts+header payload decode error. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -594,13 +972,60 @@ struct TSPacket
|
||||||
payload->size - payload->pointer_field_size);
|
payload->size - payload->pointer_field_size);
|
||||||
|
|
||||||
return finish();
|
return finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TSPacket::finish()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSHeader::TSHeader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TSHeader::~TSHeader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TSHeader::get_size()
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TSHeader::demux(TSContext* ctx, TSPacket* pkt, u_int8_t* start, u_int8_t* last, u_int8_t*& p)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
// ts packet header.
|
||||||
|
sync_byte = *p++;
|
||||||
|
if (sync_byte != 0x47) {
|
||||||
|
trace("ts+sync_bytes invalid sync_bytes: %#x, expect is 0x47", sync_byte);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int finish()
|
pid = 0;
|
||||||
{
|
((char*)&pid)[1] = *p++;
|
||||||
return 0;
|
((char*)&pid)[0] = *p++;
|
||||||
}
|
|
||||||
};
|
transport_error_indicator = (pid >> 15) & 0x01;
|
||||||
|
payload_unit_start_indicator = (pid >> 14) & 0x01;
|
||||||
|
transport_priority = (pid >> 13) & 0x01;
|
||||||
|
pid &= 0x1FFF;
|
||||||
|
|
||||||
|
ctx->push(TSPidTypePAT, pid);
|
||||||
|
|
||||||
|
continuity_counter = *p++;
|
||||||
|
|
||||||
|
transport_scrambling_control = (continuity_counter >> 6) & 0x03;
|
||||||
|
adaption_field_control = (continuity_counter >> 4) & 0x03;
|
||||||
|
continuity_counter &= 0x0F;
|
||||||
|
|
||||||
|
trace("ts+header sync: %#x error: %d unit_start: %d priotiry: %d pid: %d scrambling: %d adaption: %d counter: %d",
|
||||||
|
sync_byte, transport_error_indicator, payload_unit_start_indicator, transport_priority, pid,
|
||||||
|
transport_scrambling_control, adaption_field_control, continuity_counter);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int /*argc*/, char** /*argv*/)
|
int main(int /*argc*/, char** /*argv*/)
|
||||||
{
|
{
|
||||||
|
@ -610,6 +1035,8 @@ int main(int /*argc*/, char** /*argv*/)
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
trace("demuxer+read packet count offset T+0 T+1 T+2 T+3 T+x T+L2 T+L1 T+L0");
|
trace("demuxer+read packet count offset T+0 T+1 T+2 T+3 T+x T+L2 T+L1 T+L0");
|
||||||
|
|
||||||
|
TSContext ctx;
|
||||||
for (int i = 0, offset = 0; ; i++) {
|
for (int i = 0, offset = 0; ; i++) {
|
||||||
u_int8_t ts_packet[TS_PACKET_SIZE];
|
u_int8_t ts_packet[TS_PACKET_SIZE];
|
||||||
memset(ts_packet, 0, sizeof(ts_packet));
|
memset(ts_packet, 0, sizeof(ts_packet));
|
||||||
|
@ -632,7 +1059,7 @@ int main(int /*argc*/, char** /*argv*/)
|
||||||
u_int8_t* last = ts_packet + TS_PACKET_SIZE;
|
u_int8_t* last = ts_packet + TS_PACKET_SIZE;
|
||||||
|
|
||||||
TSPacket pkt;
|
TSPacket pkt;
|
||||||
if ((ret = pkt.demux(start, last, p)) != 0) {
|
if ((ret = pkt.demux(&ctx, start, last, p)) != 0) {
|
||||||
trace("demuxer+read decode ts packet error. ret=%d", ret);
|
trace("demuxer+read decode ts packet error. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,9 @@ file
|
||||||
..\core\srs_core_pithy_print.hpp,
|
..\core\srs_core_pithy_print.hpp,
|
||||||
..\core\srs_core_pithy_print.cpp,
|
..\core\srs_core_pithy_print.cpp,
|
||||||
..\core\srs_core_log.hpp,
|
..\core\srs_core_log.hpp,
|
||||||
..\core\srs_core_log.cpp;
|
..\core\srs_core_log.cpp,
|
||||||
|
research readonly separator,
|
||||||
|
..\..\research\ts_info.cpp;
|
||||||
mainconfig
|
mainconfig
|
||||||
"" = "MAIN";
|
"" = "MAIN";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue