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,
{
MpegTSSectionFilter *tss = &tss1->u.section_filter;
int len;
- unsigned int crc;
if (is_start) {
memcpy(tss->section_buf, buf, buf_size);
}
if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) {
- if (tss->check_crc) {
- crc = mpegts_crc32(tss->section_buf, tss->section_h_size);
- if (crc != 0)
- goto invalid_crc;
- }
- tss->section_cb(tss->opaque, tss->section_buf, tss->section_h_size);
- invalid_crc:
tss->end_of_section_reached = 1;
+ if (!tss->check_crc ||
+ mpegts_crc32(tss->section_buf, tss->section_h_size) == 0)
+ tss->section_cb(tss->opaque, tss->section_buf, tss->section_h_size);
}
}
{
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 = 0, anc_page = 0; /* initialize to kill warnings */
+ char language[4];
#ifdef DEBUG_SI
printf("PMT:\n");
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;
+ desc_list_end = p + desc_list_len;
+ if (desc_list_end > p_end)
break;
- p += desc_length;
- if (p > p_end)
- return;
+ 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);
case STREAM_TYPE_VIDEO_H264:
case STREAM_TYPE_AUDIO_AAC:
case STREAM_TYPE_AUDIO_AC3:
- add_pes_stream(ts, pid, stream_type);
+ case STREAM_TYPE_AUDIO_DTS:
+ 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);
#define PES_START_SIZE 9
#define MAX_PES_HEADER_SIZE (9 + 255)
-typedef struct PESContext {
+struct PESContext {
int pid;
int stream_type;
MpegTSContext *ts;
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)
{
{
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;
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;
- 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) {
- 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];
}
}
-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;
/* 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;
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
if (!tss) {
av_free(pes);
- return -1;
+ return 0;
}
- return 0;
+ return pes;
}
/* handle one TS packet */
if (p + len > p_end)
return;
if (len && cc_ok) {
- /* write remaning section bytes */
+ /* write remaining section bytes */
write_section_data(s, tss,
p, len, 0);
+ /* check whether filter has been closed */
+ if (!ts->pids[pid])
+ return;
}
p += len;
if (p < p_end) {
MpegTSContext *ts = s->priv_data;
ByteIOContext *pb = &s->pb;
uint8_t buf[1024];
- int len, sid;
+ int len, sid, i;
int64_t pos;
MpegTSService *service;
-
+
if (ap) {
ts->mpeg2ts_raw = ap->mpeg2ts_raw;
ts->mpeg2ts_compute_pcr = ap->mpeg2ts_compute_pcr;
}
if (ts->nb_services <= 0) {
- /* raw transport stream */
- ts->auto_guess = 1;
- s->ctx_flags |= AVFMTCTX_NOHEADER;
- goto do_pcr;
- }
+ /* raw transport stream */
+ ts->auto_guess = 1;
+ s->ctx_flags |= AVFMTCTX_NOHEADER;
+ goto do_pcr;
+ }
/* tune to first service found */
- service = ts->services[0];
- sid = service->sid;
+ for(i=0; i<ts->nb_services && ts->set_service_ret; i++){
+ service = ts->services[i];
+ sid = service->sid;
#ifdef DEBUG_SI
- printf("tuning to '%s'\n", service->name);
+ printf("tuning to '%s'\n", service->name);
#endif
- /* now find the info for the first service if we found any,
- otherwise try to filter all PATs */
-
- url_fseek(pb, pos, SEEK_SET);
- mpegts_set_service(ts, sid, set_service_cb, ts);
-
- handle_packets(ts, MAX_SCAN_PACKETS);
-
+ /* now find the info for the first service if we found any,
+ otherwise try to filter all PATs */
+
+ url_fseek(pb, pos, SEEK_SET);
+ mpegts_set_service(ts, sid, set_service_cb, ts);
+
+ handle_packets(ts, MAX_SCAN_PACKETS);
+ }
/* if could not find service, exit */
+
if (ts->set_service_ret != 0)
return -1;
uint8_t packet[TS_PACKET_SIZE];
/* only read packets */
-
- s->pts_num = 1;
- s->pts_den = 27000000;
do_pcr:
st = av_new_stream(s, 0);
if (!st)
goto fail;
- st->codec.codec_type = CODEC_TYPE_DATA;
- st->codec.codec_id = CODEC_ID_MPEG2TS;
+ av_set_pts_info(st, 60, 1, 27000000);
+ st->codec->codec_type = CODEC_TYPE_DATA;
+ st->codec->codec_id = CODEC_ID_MPEG2TS;
/* we iterate until we find two PCRs to estimate the bitrate */
pcr_pid = -1;
ts->pcr_incr = (pcrs[1] - pcrs[0]) / (packet_count[1] - packet_count[0]);
ts->cur_pcr = pcrs[0] - ts->pcr_incr * packet_count[0];
s->bit_rate = (TS_PACKET_SIZE * 8) * 27e6 / ts->pcr_incr;
- st->codec.bit_rate = s->bit_rate;
- st->start_time = ts->cur_pcr * 1000000.0 / 27.0e6;
+ st->codec->bit_rate = s->bit_rate;
+ st->start_time = ts->cur_pcr;
#if 0
printf("start=%0.3f pcr=%0.3f incr=%d\n",
st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);
if (av_new_packet(pkt, TS_PACKET_SIZE) < 0)
return -ENOMEM;
+ pkt->pos= url_ftell(&s->pb);
ret = read_packet(&s->pb, pkt->data, ts->raw_packet_size);
if (ret < 0) {
av_free_packet(pkt);
}
static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
- int64_t *ppos, int find_next)
+ int64_t *ppos, int64_t pos_limit)
{
MpegTSContext *ts = s->priv_data;
int64_t pos, timestamp;
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pid;
-
- pos = *ppos;
+ const int find_next= 1;
+ pos = ((*ppos + ts->raw_packet_size - 1) / ts->raw_packet_size) * ts->raw_packet_size;
if (find_next) {
for(;;) {
url_fseek(&s->pb, pos, SEEK_SET);
}
}
*ppos = pos;
- return timestamp;
-}
-
-typedef int64_t ReadTimestampFunc(AVFormatContext *s, int stream_index,
- int64_t *ppos, int find_next);
-static int64_t do_block_align(int64_t val, int block_align)
-{
- return (val / block_align) * block_align;
+ return timestamp;
}
-/* XXX: use it in other formats */
-static int timestamp_read_seek(AVFormatContext *s,
- int stream_index, int64_t timestamp,
- ReadTimestampFunc *read_timestamp,
- int block_align)
-{
- int64_t pos_min, pos_max, pos;
- int64_t dts_min, dts_max, dts;
-
-#ifdef DEBUG_SEEK
- printf("read_seek: %d %0.3f\n", stream_index, timestamp / 90000.0);
-#endif
+static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
+ MpegTSContext *ts = s->priv_data;
+ uint8_t buf[TS_PACKET_SIZE];
+ int64_t pos;
- pos_min = 0;
- dts_min = read_timestamp(s, stream_index, &pos_min, 1);
- if (dts_min == AV_NOPTS_VALUE) {
- /* we can reach this case only if no PTS are present in
- the whole stream */
+ if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
return -1;
- }
- pos_max = do_block_align(url_filesize(url_fileno(&s->pb)), block_align) -
- block_align;
- dts_max = read_timestamp(s, stream_index, &pos_max, 0);
-
- while (pos_min <= pos_max) {
-#ifdef DEBUG_SEEK
- printf("pos_min=0x%llx pos_max=0x%llx dts_min=%0.3f dts_max=%0.3f\n",
- pos_min, pos_max,
- dts_min / 90000.0, dts_max / 90000.0);
-#endif
- if (timestamp <= dts_min) {
- pos = pos_min;
- goto found;
- } else if (timestamp >= dts_max) {
- pos = pos_max;
- goto found;
- } else {
- /* interpolate position (better than dichotomy) */
- pos = (int64_t)((double)(pos_max - pos_min) *
- (double)(timestamp - dts_min) /
- (double)(dts_max - dts_min)) + pos_min;
- pos = do_block_align(pos, block_align);
- }
-#ifdef DEBUG_SEEK
- printf("pos=0x%llx\n", pos);
-#endif
- /* read the next timestamp */
- dts = read_timestamp(s, stream_index, &pos, 1);
- /* check if we are lucky */
- if (dts == AV_NOPTS_VALUE) {
- /* should never happen */
- pos = pos_min;
- goto found;
- } else if (timestamp == dts) {
- goto found;
- } else if (timestamp < dts) {
- pos_max = pos;
- dts_max = read_timestamp(s, stream_index, &pos_max, 0);
- if (dts_max == AV_NOPTS_VALUE) {
- /* should never happen */
- break;
- } else if (timestamp >= dts_max) {
- pos = pos_max;
- goto found;
- }
- } else {
- pos_min = pos + block_align;
- dts_min = read_timestamp(s, stream_index, &pos_min, 1);
- if (dts_min == AV_NOPTS_VALUE) {
- /* should never happen */
- goto found;
- } else if (timestamp <= dts_min) {
- goto found;
- }
- }
- }
- pos = pos_min;
- found:
-#ifdef DEBUG_SEEK
- pos_min = pos;
- dts_min = read_timestamp(s, stream_index, &pos_min, 1);
- pos_min += block_align;
- dts_max = read_timestamp(s, stream_index, &pos_min, 1);
- printf("pos=0x%llx %0.3f<=%0.3f<=%0.3f\n",
- pos, dts_min / 90000.0, timestamp / 90000.0, dts_max / 90000.0);
-#endif
- /* do the seek */
- url_fseek(&s->pb, pos, SEEK_SET);
- return 0;
-}
-static int mpegts_read_seek(AVFormatContext *s,
- int stream_index, int64_t timestamp)
-{
- MpegTSContext *ts = s->priv_data;
+ pos= url_ftell(&s->pb);
- timestamp = (timestamp * 90000) / AV_TIME_BASE;
+ for(;;) {
+ url_fseek(&s->pb, pos, SEEK_SET);
+ if (get_buffer(&s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
+ return -1;
+// pid = ((buf[1] & 0x1f) << 8) | buf[2];
+ if(buf[1] & 0x40) break;
+ pos += ts->raw_packet_size;
+ }
+ url_fseek(&s->pb, pos, SEEK_SET);
- return timestamp_read_seek(s, stream_index, timestamp,
- mpegts_get_pcr, ts->raw_packet_size);
+ return 0;
}
/**************************************************************/
mpegts_read_header,
mpegts_read_packet,
mpegts_read_close,
- mpegts_read_seek,
+ read_seek,
+ mpegts_get_pcr,
.flags = AVFMT_SHOW_IDS,
};