cosmetic change in resync code - added PAT scanning code if no SDT is found (in the...
authorFabrice Bellard <fabrice@bellard.org>
Tue, 15 Jul 2003 13:21:39 +0000 (13:21 +0000)
committerFabrice Bellard <fabrice@bellard.org>
Tue, 15 Jul 2003 13:21:39 +0000 (13:21 +0000)
Originally committed as revision 2043 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/mpegts.c

index 96b2d39..2fd8bf8 100644 (file)
 //#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 */