[linux-dvb] szap-pmt.diff

Matthias Mueller matthias.mueller at rz.uni-karlsruhe.de
Sat Jun 11 20:43:33 CEST 2005


Hi,

On Sat, Jun 11, 2005 at 01:36:03PM +0200, Grégoire Favre wrote:
> On Sat, Jun 11, 2005 at 01:29:44PM +0200, Matthias Mueller wrote:
> 
> > This patch was just a quick hack and shouldn't go into CVS (that's the
> > reason I didn't send it to the mailinglist). A proper solution would be to
> > lookup the pmt-pid in the pat for the tuned channel, so the user doesn't
> > have to specify the pmt-pid himself. 
> 
> Oops, sorry, thank for correcting me :)

A new version of my patch is attached to this mail. It adds an option to
szap to include the pat/pmt packets when tuning to a channel and record
via /dev/dvb/adapterX/dvr0. This is needed to correctly identify h264
streams in mplayer (without the information from the pmt, mplayer assumes
mpeg2-video).

This patch relies on the correct session_id in channels.conf (directly
after the apid), otherwise it won't find the correct pid for the pmt
and will print an error message.

The entry for the h264 teststreams of premiere is:
DPC.TV11:11914:h:0:27500:767:772:129

With szap -p DPC.TV11 mplayer correctly identifies the the stream as:
VIDEO H264(pid=767)...AUDIO A52(pid=772) NO SUBS (yet)!  PROGRAM N. 129

The code for pat-parsing is taken from scan.c, the errors are from me ;-)

Bye,
Matthias 
-------------- next part --------------
--- szap.c.orig	2005-06-11 09:42:05.000000000 +0200
+++ szap.c	2005-06-11 20:28:12.000000000 +0200
@@ -84,13 +84,14 @@
     "     -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
     "     -l low[,high[,switch]] in Mhz\n"
     "     -i        : run interactively, allowing you to type in channel names\n"
+    "     -p        : add pat and pmt to TS recording (implies -r)\n"
     "                 or -n numbers for zapping\n";
 
 static int set_demux(int dmxfd, int pid, int audio, int dvr)
 {
    struct dmx_pes_filter_params pesfilter;
 
-   if (pid <= 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
+   if (pid < 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
 	   return TRUE;
 
    if (dvr) {
@@ -102,7 +103,7 @@
    pesfilter.pid = pid;
    pesfilter.input = DMX_IN_FRONTEND;
    pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
-   pesfilter.pes_type = audio ? DMX_PES_AUDIO : DMX_PES_VIDEO;
+   pesfilter.pes_type = audio;
    pesfilter.flags = DMX_IMMEDIATE_START;
 
    if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
@@ -114,6 +115,65 @@
    return TRUE;
 }
 
+int get_pmt(char *dmxdev, int sid)
+{
+   int patfd,count;
+   int pmt=0;
+   int patread=0;
+   int section_length;
+   unsigned char buft[4096];
+   unsigned char *buf = buft;
+   struct dmx_sct_filter_params f;
+
+   memset(&f, 0, sizeof(f));
+   f.pid = 0;
+   f.filter.filter[0] = (uint8_t) 0x42;
+   f.filter.filter[0] = 0xff;
+   f.timeout = 0;
+   f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
+
+   if ((patfd = open(dmxdev, O_RDWR)) < 0) {
+      perror("openening pat demux failed");
+      return -1;
+   }
+
+   if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
+      perror("ioctl DMX_SET_FILTER failed");
+      close(patfd);
+      return -1;
+   }
+
+   while (!patread){
+      if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
+         count = read(patfd, buf, sizeof(buft));
+      if (count < 0) {
+         perror("read_sections: read error");
+         close(patfd);
+         return -1;
+      }
+
+      section_length = ((buf[1] & 0x0f) << 8) | buf[2];
+      if (count != section_length + 3)
+         continue;
+
+      buf+=8;
+      section_length-=8;
+
+      patread=1; /* assumes one section contains the whole pat */
+      while (section_length > 0) {
+         int service_id = (buf[0] << 8) | buf[1];
+         if (service_id == sid) {
+            pmt = ((buf[2] & 0x1f) << 8) | buf[3];
+            section_length = 0;
+         }
+         buf += 4;
+         section_length -= 4;
+     }
+   }
+
+   close(patfd);
+   return pmt;
+}
 
 struct diseqc_cmd {
    struct dvb_diseqc_master_cmd cmd;
@@ -230,10 +290,12 @@
 static
 int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
       unsigned int sat_no, unsigned int freq, unsigned int pol,
-      unsigned int sr, unsigned int vpid, unsigned int apid, int dvr)
+      unsigned int sr, unsigned int vpid, unsigned int apid, int sid, 
+      int dvr, int pmt)
 {
    char fedev[128], dmxdev[128];
-   static int fefd, videofd, audiofd;
+   static int fefd, videofd, audiofd, patfd, pmtfd;
+   int pmtpid;
    uint32_t ifreq;
    int hiband, result;
    static struct dvb_frontend_info fe_info;
@@ -274,6 +336,25 @@
 	 close(fefd);
 	 return FALSE;
       }
+
+      if (pmt){
+         if ((patfd = open(dmxdev, O_RDWR)) < 0) {
+	    perror("opening audio demux failed");
+	    close(audiofd);
+	    close(videofd);
+	    close(fefd);
+	    return FALSE;
+         }
+
+         if ((pmtfd = open(dmxdev, O_RDWR)) < 0) {
+  	    perror("opening audio demux failed");
+    	    close(patfd);
+    	    close(audiofd);
+    	    close(videofd);
+  	    close(fefd);
+  	    return FALSE;
+         }
+      }
    }
 
    hiband = 0;
@@ -293,13 +374,30 @@
 
    if (diseqc(fefd, sat_no, pol, hiband))
       if (do_tune(fefd, ifreq, sr))
-	 if (set_demux(videofd, vpid, 0, dvr))
-	    if (set_demux(audiofd, apid, 1, dvr))
-	       result = TRUE;
+	 if (set_demux(videofd, vpid, DMX_PES_OTHER, dvr))
+	    if (set_demux(audiofd, apid, DMX_PES_OTHER, dvr)) {
+	       if (pmt) {
+	           pmtpid=get_pmt(dmxdev, sid);
+		   if (pmtpid < 0) {
+		      result = FALSE;
+		   }
+		   if (pmtpid == 0) {
+		      fprintf(stderr,"couldn't find pmt for sid %04x\n",sid);
+		      result = FALSE;
+		   }
+       	           if (set_demux(patfd, 0, DMX_PES_OTHER, dvr))
+	              if (set_demux(pmtfd, pmtpid, DMX_PES_OTHER, dvr))
+	                 result = TRUE;
+		} else {
+		  result = TRUE;
+		}
+	    }
 
    check_frontend (fefd, dvr);
 
    if (!interactive) {
+      close(patfd);
+      close(pmtfd);
       close(audiofd);
       close(videofd);
       close(fefd);
@@ -312,14 +410,14 @@
 static int read_channels(const char *filename, int list_channels,
 			 uint32_t chan_no, const char *chan_name,
 			 unsigned int adapter, unsigned int frontend,
-			 unsigned int demux, int dvr)
+			 unsigned int demux, int dvr, int pmt)
 {
    FILE *cfp;
    char buf[4096];
    char inp[256];
    char *field, *tmp, *p;
    unsigned int line;
-   unsigned int freq, pol, sat_no, sr, vpid, apid;
+   unsigned int freq, pol, sat_no, sr, vpid, apid, sid;
    int ret;
 
 again:
@@ -405,14 +503,19 @@
 
 	 apid = strtoul(field, NULL, 0);
 
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 sid = strtoul(field, NULL, 0);
+
 	 printf("sat %u, frequency = %u MHz %c, symbolrate %u, "
-		"vpid = 0x%04x, apid = 0x%04x\n",
-		sat_no, freq, pol ? 'V' : 'H', sr, vpid, apid);
+		"vpid = 0x%04x, apid = 0x%04x sid = 0x%04x\n",
+		sat_no, freq, pol ? 'V' : 'H', sr, vpid, apid, sid);
 
 	 fclose(cfp);
 
 	 ret = zap_to(adapter, frontend, demux,
-		      sat_no, freq * 1000, pol, sr, vpid, apid, dvr);
+		      sat_no, freq * 1000, pol, sr, vpid, apid, sid, dvr, pmt);
 	 if (interactive)
 	    goto again;
 
@@ -475,11 +578,11 @@
    int list_channels = 0;
    unsigned int chan_no = 0;
    const char *chan_name = NULL;
-   unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0;
+   unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0, pmt = 0;
    int opt, copt = 0;
 
    lnb_type = *lnb_enum(0);
-   while ((opt = getopt(argc, argv, "hqrn:a:f:d:c:l:xi")) != -1) {
+   while ((opt = getopt(argc, argv, "hqrpn:a:f:d:c:l:xi")) != -1) {
       switch (opt)
       {
 	 case '?':
@@ -501,6 +604,9 @@
 	 case 'f':
 	    frontend = strtoul(optarg, NULL, 0);
 	    break;
+	 case 'p':
+	    pmt = 1;
+	    break;
 	 case 'd':
 	    demux = strtoul(optarg, NULL, 0);
 	    break;
@@ -551,8 +657,11 @@
 
    printf("reading channels from file '%s'\n", chanfile);
 
+   if (pmt)
+      dvr=1;
+
    if (!read_channels(chanfile, list_channels, chan_no, chan_name,
-	    adapter, frontend, demux, dvr))
+	    adapter, frontend, demux, dvr, pmt))
       return TRUE;
 
    return FALSE;


More information about the linux-dvb mailing list