# HG changeset patch # User bellard # Date 1058275299 0 # Node ID 0543d27721c188973e613649f3cf823d7828f047 # Parent 7c084ad75a99864e5ca18160176f365e92da06ca 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 diff -r 7c084ad75a99 -r 0543d27721c1 mpegts.c --- a/mpegts.c Sat Jul 12 16:55:15 2003 +0000 +++ b/mpegts.c Tue Jul 15 13:21:39 2003 +0000 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } +/* 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 @@ 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 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 @@ 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 @@ 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 */