|
|
|
@ -30,7 +30,10 @@ |
|
|
|
|
synchronisation is lost */ |
|
|
|
|
#define MAX_RESYNC_SIZE 4096 |
|
|
|
|
|
|
|
|
|
static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type); |
|
|
|
|
typedef struct PESContext PESContext; |
|
|
|
|
|
|
|
|
|
static PESContext* add_pes_stream(MpegTSContext *ts, int pid, int stream_type); |
|
|
|
|
static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code); |
|
|
|
|
|
|
|
|
|
enum MpegTSFilterType { |
|
|
|
|
MPEGTS_PES, |
|
|
|
@ -368,8 +371,13 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) |
|
|
|
|
{ |
|
|
|
|
MpegTSContext *ts = opaque; |
|
|
|
|
SectionHeader h1, *h = &h1; |
|
|
|
|
const uint8_t *p, *p_end; |
|
|
|
|
int program_info_length, pcr_pid, pid, stream_type, desc_length; |
|
|
|
|
PESContext *pes; |
|
|
|
|
AVStream *st; |
|
|
|
|
const uint8_t *p, *p_end, *desc_list_end, *desc_end; |
|
|
|
|
int program_info_length, pcr_pid, pid, stream_type; |
|
|
|
|
int desc_list_len, desc_len, desc_tag; |
|
|
|
|
int comp_page, anc_page; |
|
|
|
|
char language[4]; |
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_SI |
|
|
|
|
printf("PMT:\n"); |
|
|
|
@ -399,18 +407,57 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) |
|
|
|
|
if (p >= p_end) |
|
|
|
|
return; |
|
|
|
|
for(;;) { |
|
|
|
|
language[0] = 0; |
|
|
|
|
st = 0; |
|
|
|
|
stream_type = get8(&p, p_end); |
|
|
|
|
if (stream_type < 0) |
|
|
|
|
break; |
|
|
|
|
pid = get16(&p, p_end) & 0x1fff; |
|
|
|
|
if (pid < 0) |
|
|
|
|
break; |
|
|
|
|
desc_length = get16(&p, p_end) & 0xfff; |
|
|
|
|
if (desc_length < 0) |
|
|
|
|
desc_list_len = get16(&p, p_end) & 0xfff; |
|
|
|
|
if (desc_list_len < 0) |
|
|
|
|
break; |
|
|
|
|
p += desc_length; |
|
|
|
|
if (p > p_end) |
|
|
|
|
return; |
|
|
|
|
desc_list_end = p + desc_list_len; |
|
|
|
|
if (desc_list_end > p_end) |
|
|
|
|
break; |
|
|
|
|
for(;;) { |
|
|
|
|
desc_tag = get8(&p, desc_list_end); |
|
|
|
|
if (desc_tag < 0) |
|
|
|
|
break; |
|
|
|
|
desc_len = get8(&p, desc_list_end); |
|
|
|
|
desc_end = p + desc_len; |
|
|
|
|
if (desc_end > desc_list_end) |
|
|
|
|
break; |
|
|
|
|
#ifdef DEBUG_SI |
|
|
|
|
printf("tag: 0x%02x len=%d\n", desc_tag, desc_len); |
|
|
|
|
#endif |
|
|
|
|
switch(desc_tag) { |
|
|
|
|
case DVB_SUBT_DESCID: |
|
|
|
|
if (stream_type == STREAM_TYPE_PRIVATE_DATA) |
|
|
|
|
stream_type = STREAM_TYPE_SUBTITLE_DVB; |
|
|
|
|
|
|
|
|
|
language[0] = get8(&p, desc_end); |
|
|
|
|
language[1] = get8(&p, desc_end); |
|
|
|
|
language[2] = get8(&p, desc_end); |
|
|
|
|
language[3] = 0; |
|
|
|
|
get8(&p, desc_end); |
|
|
|
|
comp_page = get16(&p, desc_end); |
|
|
|
|
anc_page = get16(&p, desc_end); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
case 0x0a: /* ISO 639 language descriptor */ |
|
|
|
|
language[0] = get8(&p, desc_end); |
|
|
|
|
language[1] = get8(&p, desc_end); |
|
|
|
|
language[2] = get8(&p, desc_end); |
|
|
|
|
language[3] = 0; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
p = desc_end; |
|
|
|
|
} |
|
|
|
|
p = desc_list_end; |
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_SI |
|
|
|
|
printf("stream_type=%d pid=0x%x\n", stream_type, pid); |
|
|
|
@ -427,12 +474,28 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) |
|
|
|
|
case STREAM_TYPE_AUDIO_AAC: |
|
|
|
|
case STREAM_TYPE_AUDIO_AC3: |
|
|
|
|
case STREAM_TYPE_AUDIO_DTS: |
|
|
|
|
add_pes_stream(ts, pid, stream_type); |
|
|
|
|
case STREAM_TYPE_SUBTITLE_DVB: |
|
|
|
|
pes = add_pes_stream(ts, pid, stream_type); |
|
|
|
|
if (pes) |
|
|
|
|
st = new_pes_av_stream(pes, 0); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
/* we ignore the other streams */ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (st) { |
|
|
|
|
if (language[0] != 0) { |
|
|
|
|
st->language[0] = language[0]; |
|
|
|
|
st->language[1] = language[1]; |
|
|
|
|
st->language[2] = language[2]; |
|
|
|
|
st->language[3] = language[3]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (stream_type == STREAM_TYPE_SUBTITLE_DVB) { |
|
|
|
|
st->codec.sub_id = (anc_page << 16) | comp_page; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/* all parameters are there */ |
|
|
|
|
ts->set_service_cb(ts->set_service_opaque, 0); |
|
|
|
@ -653,7 +716,7 @@ enum MpegTSState { |
|
|
|
|
#define PES_START_SIZE 9 |
|
|
|
|
#define MAX_PES_HEADER_SIZE (9 + 255) |
|
|
|
|
|
|
|
|
|
typedef struct PESContext { |
|
|
|
|
struct PESContext { |
|
|
|
|
int pid; |
|
|
|
|
int stream_type; |
|
|
|
|
MpegTSContext *ts; |
|
|
|
@ -666,7 +729,7 @@ typedef struct PESContext { |
|
|
|
|
int pes_header_size; |
|
|
|
|
int64_t pts, dts; |
|
|
|
|
uint8_t header[MAX_PES_HEADER_SIZE]; |
|
|
|
|
} PESContext; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static int64_t get_pts(const uint8_t *p) |
|
|
|
|
{ |
|
|
|
@ -687,9 +750,8 @@ static void mpegts_push_data(void *opaque, |
|
|
|
|
{ |
|
|
|
|
PESContext *pes = opaque; |
|
|
|
|
MpegTSContext *ts = pes->ts; |
|
|
|
|
AVStream *st; |
|
|
|
|
const uint8_t *p; |
|
|
|
|
int len, code, codec_type, codec_id; |
|
|
|
|
int len, code; |
|
|
|
|
|
|
|
|
|
if (is_start) { |
|
|
|
|
pes->state = MPEGTS_HEADER; |
|
|
|
@ -722,59 +784,7 @@ static void mpegts_push_data(void *opaque, |
|
|
|
|
goto skip; |
|
|
|
|
if (!pes->st) { |
|
|
|
|
/* allocate stream */ |
|
|
|
|
switch(pes->stream_type){ |
|
|
|
|
case STREAM_TYPE_AUDIO_MPEG1: |
|
|
|
|
case STREAM_TYPE_AUDIO_MPEG2: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_MP3; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_VIDEO_MPEG1: |
|
|
|
|
case STREAM_TYPE_VIDEO_MPEG2: |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_MPEG2VIDEO; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_VIDEO_MPEG4: |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_MPEG4; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_VIDEO_H264: |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_H264; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_AUDIO_AAC: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_AAC; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_AUDIO_AC3: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_AC3; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_AUDIO_DTS: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_DTS; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
if (code >= 0x1c0 && code <= 0x1df) { |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_MP2; |
|
|
|
|
} else if (code == 0x1bd) { |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_AC3; |
|
|
|
|
} else { |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_MPEG1VIDEO; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
st = av_new_stream(pes->stream, pes->pid); |
|
|
|
|
if (st) { |
|
|
|
|
av_set_pts_info(st, 33, 1, 90000); |
|
|
|
|
st->priv_data = pes; |
|
|
|
|
st->codec.codec_type = codec_type; |
|
|
|
|
st->codec.codec_id = codec_id; |
|
|
|
|
st->need_parsing = 1; |
|
|
|
|
pes->st = st; |
|
|
|
|
} |
|
|
|
|
new_pes_av_stream(pes, code); |
|
|
|
|
} |
|
|
|
|
pes->state = MPEGTS_PESHEADER_FILL; |
|
|
|
|
pes->total_size = (pes->header[4] << 8) | pes->header[5]; |
|
|
|
@ -854,7 +864,73 @@ static void mpegts_push_data(void *opaque, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type) |
|
|
|
|
static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code) |
|
|
|
|
{ |
|
|
|
|
AVStream *st; |
|
|
|
|
int codec_type, codec_id; |
|
|
|
|
|
|
|
|
|
switch(pes->stream_type){ |
|
|
|
|
case STREAM_TYPE_AUDIO_MPEG1: |
|
|
|
|
case STREAM_TYPE_AUDIO_MPEG2: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_MP3; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_VIDEO_MPEG1: |
|
|
|
|
case STREAM_TYPE_VIDEO_MPEG2: |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_MPEG2VIDEO; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_VIDEO_MPEG4: |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_MPEG4; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_VIDEO_H264: |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_H264; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_AUDIO_AAC: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_AAC; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_AUDIO_AC3: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_AC3; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_AUDIO_DTS: |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_DTS; |
|
|
|
|
break; |
|
|
|
|
case STREAM_TYPE_SUBTITLE_DVB: |
|
|
|
|
codec_type = CODEC_TYPE_SUBTITLE; |
|
|
|
|
codec_id = CODEC_ID_DVB_SUBTITLE; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
if (code >= 0x1c0 && code <= 0x1df) { |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_MP2; |
|
|
|
|
} else if (code == 0x1bd) { |
|
|
|
|
codec_type = CODEC_TYPE_AUDIO; |
|
|
|
|
codec_id = CODEC_ID_AC3; |
|
|
|
|
} else { |
|
|
|
|
codec_type = CODEC_TYPE_VIDEO; |
|
|
|
|
codec_id = CODEC_ID_MPEG1VIDEO; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
st = av_new_stream(pes->stream, pes->pid); |
|
|
|
|
if (st) { |
|
|
|
|
av_set_pts_info(st, 33, 1, 90000); |
|
|
|
|
st->priv_data = pes; |
|
|
|
|
st->codec.codec_type = codec_type; |
|
|
|
|
st->codec.codec_id = codec_id; |
|
|
|
|
st->need_parsing = 1; |
|
|
|
|
pes->st = st; |
|
|
|
|
} |
|
|
|
|
return st; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int stream_type) |
|
|
|
|
{ |
|
|
|
|
MpegTSFilter *tss; |
|
|
|
|
PESContext *pes; |
|
|
|
@ -862,7 +938,7 @@ static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type) |
|
|
|
|
/* if no pid found, then add a pid context */ |
|
|
|
|
pes = av_mallocz(sizeof(PESContext)); |
|
|
|
|
if (!pes) |
|
|
|
|
return -1; |
|
|
|
|
return 0; |
|
|
|
|
pes->ts = ts; |
|
|
|
|
pes->stream = ts->stream; |
|
|
|
|
pes->pid = pid; |
|
|
|
@ -870,9 +946,9 @@ static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type) |
|
|
|
|
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); |
|
|
|
|
if (!tss) { |
|
|
|
|
av_free(pes); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
return pes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* handle one TS packet */ |
|
|
|
|