从PMT表中获取Video PID的函数代码
GetPmtPid函数的实现见:http://blog.youkuaiyun.com/myaccella/article/details/6982596
#define MAKE_PID(p) (((p[0]<<8) + p[1]) & 0x1fff)
#define MAKE_WORD(h, l) (((h) << 8) | (l))
Little endian 的结构定义
typedef struct {
unsigned stream_type :8;
unsigned elementary_PID_high :5;
unsigned :3;
unsigned elementary_PID_low :8;
unsigned ES_info_length_high :4;
unsigned :4;
unsigned ES_info_length_low :8;
}MpegPmtStream_t;
typedef struct {
unsigned table_id :8;
unsigned section_length_high :4;
unsigned :2;
unsigned :1;
unsigned section_syntax_indicator :1;
unsigned section_length_low :8;
unsigned program_number_high :8;
unsigned program_number_low :8;
unsigned current_next_indicator :1;
unsigned version_number :5;
unsigned :2;
unsigned section_number :8;
unsigned last_section_number :8;
unsigned PCR_PID_high :5;
unsigned :3;
unsigned PCR_PID_low :8;
unsigned program_info_length_high :4;
unsigned :4;
unsigned program_info_length_low :8;
}MpegPmtHeader_t;
ushort GetVideoPid(const char* filename)
{
#define TSPACKET_SIZE 188
#define CRC_SIZE 4
ushort pid, pmtpid, videopid = 0;
uchar buf[TSPACKET_SIZE];
uchar* p = buf;
MpegPmtHeader_t* header;
MpegPmtStream_t* stream;
FILE* fp;
int pos = 0;
ushort section_len;
pmtpid = GetPmtPid(filename);
if (pmtpid == 0) {
fprintf(stderr, "Unable to get PMT PID!\n");
return 0;
}
fp = fopen(filename, "rb");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file %s: %s\n", filename, strerror(errno));
return 0;
}
while (fread(buf, 1, TSPACKET_SIZE, fp) == TSPACKET_SIZE) {
if (buf[0] != MPEG_TS_SYNC_BYTE) { // @MPEG_TS_SYNC_BYTE = 0x47
fprintf(stderr, "No sync byte!\n");
break;
}
p = buf;
pid = MAKE_PID((p+1));
if( pid != pmtpid ) {
// Not a PMT packet
continue;
}
// payload_unit_start_indicator 必须为1
if (!(buf[1] >> 6 & 0x01)) {
fprintf(stderr, "No payload_unit_start_indicator!\n");
continue;
}
// Skip the TS header
p += MPEG_TS_HEADER_SIZE; //@MPEG_TS_HEADER_SIZE = 4
// Adaptation field exist or not
if ((buf[3] >> 4 & 0x03) & 0x2) {
fprintf(stderr, "Adaptation field exist\n");
p += 1 + p[0]; // p[0]是Adaptation field长度, 1为长度域
}
// p[0] 为 Point field长度, 1为Point field
p += 1 + p[0];
// Now p 指向 PMT表头
header = (MpegPmtHeader_t*)p;
pos += sizeof(MpegPmtHeader_t);
pos += MAKE_WORD(header->program_info_length_high, header->program_info_length_low);;
// Parse stream table
section_len = MAKE_WORD(header->section_length_high, header->section_length_low);
while (pos < (section_len + 2) - CRC_SIZE) {
stream = (MpegPmtStream_t*)(p + pos);
// @MPEG_TS_STREAM_TYPE_VIDEO_2 = 0x02
if (stream->stream_type == MPEG_TS_STREAM_TYPE_VIDEO_2) {
videopid = MAKE_WORD(stream->elementary_PID_high, stream->elementary_PID_low);
break;
}
// @MPEG_PMT_STREAM_HEADER_SIZE = 5
pos += MPEG_PMT_STREAM_HEADER_SIZE
+ MAKE_WORD(stream->ES_info_length_high, stream->ES_info_length_low);
}
}
fclose(fp);
return videopid;
}