summaryrefslogtreecommitdiff
path: root/libavformat/mpegts.c
diff options
context:
space:
mode:
authorFabrice Bellard <fabrice@bellard.org>2003-07-15 13:21:39 +0000
committerFabrice Bellard <fabrice@bellard.org>2003-07-15 13:21:39 +0000
commitfc48fe84a98ba4b7d80577d9747143e1e32188e1 (patch)
treea477de5397877da8e68ee8e9c5dbcae5d732418b /libavformat/mpegts.c
parent68a4889157d1aa5a53573171f8b024566e85127b (diff)
cosmetic change in resync code - added PAT scanning code if no SDT is found (in the futur it would be interesting to give an API to change channel - also useful for DV input number or TV grab tunning
Originally committed as revision 2043 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/mpegts.c')
-rw-r--r--libavformat/mpegts.c157
1 files changed, 121 insertions, 36 deletions
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 96b2d39645..2fd8bf8965 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -23,7 +23,11 @@
//#define DEBUG_SI
/* 1.0 second at 24Mbit/s */
-#define MAX_SCAN_PACKETS 16000
+#define MAX_SCAN_PACKETS 32000
+
+/* maximum size in which we look for synchronisation if
+ synchronisation is lost */
+#define MAX_RESYNC_SIZE 4096
static int add_pes_stream(AVFormatContext *s, int pid);
@@ -32,7 +36,6 @@ enum MpegTSFilterType {
MPEGTS_SECTION,
};
-/* XXX: suppress 'pkt' parameter */
typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start);
typedef struct MpegTSPESFilter {
@@ -432,7 +435,7 @@ static void pat_cb(void *opaque, const uint8_t *section, int section_len)
if (sid == 0x0000) {
/* NIT info */
} else {
- if (ts->req_sid == sid || ts->req_sid < 0) {
+ if (ts->req_sid == sid) {
ts->pmt_filter = mpegts_open_section_filter(ts, pmt_pid,
pmt_cb, ts, 1);
goto found;
@@ -447,6 +450,59 @@ static void pat_cb(void *opaque, const uint8_t *section, int section_len)
ts->pat_filter = NULL;
}
+/* add all services found in the PAT */
+static void pat_scan_cb(void *opaque, const uint8_t *section, int section_len)
+{
+ MpegTSContext *ts = opaque;
+ SectionHeader h1, *h = &h1;
+ const uint8_t *p, *p_end;
+ int sid, pmt_pid;
+ char *provider_name, *name;
+ char buf[256];
+
+#ifdef DEBUG_SI
+ printf("PAT:\n");
+ av_hex_dump((uint8_t *)section, section_len);
+#endif
+ p_end = section + section_len - 4;
+ p = section;
+ if (parse_section_header(h, &p, p_end) < 0)
+ return;
+ if (h->tid != PAT_TID)
+ return;
+
+ for(;;) {
+ sid = get16(&p, p_end);
+ if (sid < 0)
+ break;
+ pmt_pid = get16(&p, p_end) & 0x1fff;
+ if (pmt_pid < 0)
+ break;
+#ifdef DEBUG_SI
+ printf("sid=0x%x pid=0x%x\n", sid, pmt_pid);
+#endif
+ if (sid == 0x0000) {
+ /* NIT info */
+ } else {
+ /* add the service with a dummy name */
+ snprintf(buf, sizeof(buf), "Service %x\n", sid);
+ name = av_strdup(buf);
+ provider_name = av_strdup("");
+ if (name && provider_name) {
+ new_service(ts, sid, provider_name, name);
+ } else {
+ av_freep(&name);
+ av_freep(&provider_name);
+ }
+ }
+ }
+ ts->stop_parse = 1;
+
+ /* remove filter */
+ mpegts_close_filter(ts, ts->pat_filter);
+ ts->pat_filter = NULL;
+}
+
void mpegts_set_service(MpegTSContext *ts, int sid,
SetServiceCallback *set_service_cb, void *opaque)
{
@@ -533,13 +589,20 @@ static void sdt_cb(void *opaque, const uint8_t *section, int section_len)
ts->sdt_filter = NULL;
}
-/* scan services an a transport stream by looking at the sdt */
+/* scan services in a transport stream by looking at the SDT */
void mpegts_scan_sdt(MpegTSContext *ts)
{
ts->sdt_filter = mpegts_open_section_filter(ts, SDT_PID,
sdt_cb, ts, 1);
}
+/* scan services in a transport stream by looking at the PAT (better
+ than nothing !) */
+void mpegts_scan_pat(MpegTSContext *ts)
+{
+ ts->pat_filter = mpegts_open_section_filter(ts, PAT_PID,
+ pat_scan_cb, ts, 1);
+}
/* TS stream handling */
@@ -795,7 +858,7 @@ static void handle_packet(AVFormatContext *s, uint8_t *packet)
if (cc_ok) {
write_section_data(s, tss,
p, p_end - p, 0);
- }
+ }
}
} else {
tss->u.pes_filter.pes_cb(tss->u.pes_filter.opaque,
@@ -803,13 +866,32 @@ static void handle_packet(AVFormatContext *s, uint8_t *packet)
}
}
+/* XXX: try to find a better synchro over several packets (use
+ get_packet_size() ?) */
+static int mpegts_resync(AVFormatContext *s)
+{
+ ByteIOContext *pb = &s->pb;
+ int c, i;
+
+ for(i = 0;i < MAX_RESYNC_SIZE; i++) {
+ c = url_fgetc(pb);
+ if (c < 0)
+ return -1;
+ if (c == 0x47) {
+ url_fseek(pb, -1, SEEK_CUR);
+ return 0;
+ }
+ }
+ /* no sync found */
+ return -1;
+}
+
static int handle_packets(AVFormatContext *s, int nb_packets)
{
MpegTSContext *ts = s->priv_data;
ByteIOContext *pb = &s->pb;
uint8_t packet[TS_FEC_PACKET_SIZE];
int packet_num, len;
- int i, found = 0;
int64_t pos;
ts->stop_parse = 0;
@@ -825,26 +907,13 @@ static int handle_packets(AVFormatContext *s, int nb_packets)
if (len != ts->raw_packet_size)
return AVERROR_IO;
/* check paquet sync byte */
- if (packet[0] != 0x47)
- {
- //printf("bad packet: 0x%x\n", packet[0]);
- found = 0;
- for (i = 0; i < ts->raw_packet_size; i++)
- {
- if (packet[i] == 0x47)
- {
- found = 1;
- //printf("packet start at: %d\n", i);
- break;
- }
- }
-
- if (found)
- {
- url_fseek(pb, pos + i, SEEK_SET);
- continue;
- }
- return AVERROR_INVALIDDATA;
+ if (packet[0] != 0x47) {
+ /* find a new packet start */
+ url_fseek(pb, -ts->raw_packet_size, SEEK_CUR);
+ if (mpegts_resync(s) < 0)
+ return AVERROR_INVALIDDATA;
+ else
+ continue;
}
handle_packet(s, packet);
}
@@ -853,11 +922,19 @@ static int handle_packets(AVFormatContext *s, int nb_packets)
static int mpegts_probe(AVProbeData *p)
{
+#if 1
int size;
size = get_packet_size(p->buf, p->buf_size);
if (size < 0)
return 0;
return AVPROBE_SCORE_MAX - 1;
+#else
+ /* only use the extension for safer guess */
+ if (match_ext(p->filename, "ts"))
+ return AVPROBE_SCORE_MAX;
+ else
+ return 0;
+#endif
}
void set_service_cb(void *opaque, int ret)
@@ -873,7 +950,7 @@ static int mpegts_read_header(AVFormatContext *s,
MpegTSContext *ts = s->priv_data;
ByteIOContext *pb = &s->pb;
uint8_t buf[1024];
- int len;
+ int len, sid;
int64_t pos;
MpegTSService *service;
@@ -888,24 +965,32 @@ static int mpegts_read_header(AVFormatContext *s,
ts->auto_guess = 0;
if (!ts->auto_guess) {
- int sid = -1;
ts->set_service_ret = -1;
/* first do a scaning to get all the services */
url_fseek(pb, pos, SEEK_SET);
mpegts_scan_sdt(ts);
-
+
handle_packets(s, MAX_SCAN_PACKETS);
- if (ts->nb_services > 0)
- {
- /* tune to first service found */
- service = ts->services[0];
- sid = service->sid;
+ if (ts->nb_services <= 0) {
+ /* no SDT found, we try to look at the PAT */
+
+ url_fseek(pb, pos, SEEK_SET);
+ mpegts_scan_pat(ts);
+
+ handle_packets(s, MAX_SCAN_PACKETS);
+ }
+
+ if (ts->nb_services <= 0)
+ return -1;
+
+ /* tune to first service found */
+ service = ts->services[0];
+ 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 */