Test this patch for MPEG-TS over network/dvb streams

Nico Sabbi <[email protected]> Sat, 16 Feb 2008 02:14:06 +0100
Newsgroups gmane.comp.video.mplayer.user.dvb
Message-ID <[email protected]>
Hi,
this patch should finally make mplayer play stably and in the long run non-local
mpegts streams such as DVB and network ones; in the past those playing streams lead to a lot
of video freezes and messages like "too many packate in the buffer".
What this patch does is very simple: avoid to decode demuxed packets
until the right PCR time has been inserted in the stream.
I should use the DTS instead of the PTS to do the time validation, but since they are
always very close and since the relation
pcr < dts <= pts 
always applies, the pts serves the purpose well enough.

In practice, this patch prevents mplayer from starving data. If you are interested
in the details of this issue read the "nut broadcast" thread in [email protected].

Don't forget to add the pmt pid in the stream, or the pcr can't be identified.

Please, let me know if you experience improvements and/or regressions, and 
especially let mplayer run on the same channel for some hour before reporting
success.


Nico

_______________________________________________
MPlayer-dvb mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dvb
pcr2.diff (text/x-diff, 3.5 KB)
Index: libmpdemux/demux_ts.c
===================================================================
--- libmpdemux/demux_ts.c	(revisione 25986)
+++ libmpdemux/demux_ts.c	(copia locale)
@@ -502,7 +502,21 @@
 	return -1;
 }
 
+static inline int32_t prog_pcr_pid(ts_priv_t *priv, int progid)
+{
+	int i;
 
+	if(priv->pmt == NULL)
+		return -1;
+	for(i=0; i < priv->pmt_cnt; i++)
+	{
+		if(priv->pmt[i].progid == progid)
+			return priv->pmt[i].PCR_PID;
+	}
+	return -1;
+}
+
+
 static inline int pid_match_lang(ts_priv_t *priv, uint16_t pid, char *lang)
 {
 	uint16_t i, j;
@@ -875,6 +889,13 @@
 
 	if(video_found || audio_found)
 	{
+		if(!param->prog)
+		{
+			p = progid_for_pid(priv, video_found ? param->vpid : param->apid, 0);
+			if(p != -1)
+				param->prog = p;
+		}
+		
 		if(demuxer->stream->eof && (ret == 0))
 			ret = init_pos;
 		mp_msg(MSGT_DEMUXER, MSGL_INFO, " PROGRAM N. %d\n", param->prog);
@@ -1031,6 +1052,7 @@
 
 	start_pos = (start_pos <= priv->ts.packet_size ? 0 : start_pos - priv->ts.packet_size);
 	demuxer->movi_start = start_pos;
+	demuxer->reference_clock = MP_NOPTS_VALUE;
 	stream_reset(demuxer->stream);
 	stream_seek(demuxer->stream, start_pos);	//IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES?
 
@@ -2721,11 +2743,38 @@
 			//c==0 is allowed!
 			if(c > 0)
 			{
-				rap_flag = (stream_read_char(stream) & 0x40) >> 6;
+				uint8_t pcrbuf[188];
+				int flags = stream_read_char(stream);
+				rap_flag = (flags & 0x40) >> 6;
+				int has_pcr = flags & 0x10;
+				
 				buf_size--;
+				c--;
+				stream_read(stream, pcrbuf, c);
+
+				if(has_pcr)
+				{
+					int pcr_pid = prog_pcr_pid(priv, priv->prog);
+					if(pcr_pid == pid)
+					{
+						uint64_t pcr, pcr_ext;
 	
-				c--;
-				stream_skip(stream, c);
+						pcr  = (int64_t)(pcrbuf[0]) << 25;
+						pcr |=  pcrbuf[1]         << 17 ;
+						pcr |= (pcrbuf[2]) << 9;
+						pcr |=  pcrbuf[3]  <<  1 ;
+						pcr |= (pcrbuf[4] & 0x80) >>  7;
+	
+						pcr_ext = (pcrbuf[4] & 0x01) << 8;
+						pcr_ext |= pcrbuf[5];
+	
+						pcr = pcr * 300 + pcr_ext;
+						
+						demuxer->reference_clock = (double)pcr/(double)27000000.0;
+						//fprintf(stderr, "\r\nSET PCR: %.3lf\r\n", demuxer->reference_clock);
+					}
+				}
+				
 				buf_size -= c;
 				if(buf_size == 0)
 					continue;
Index: libmpdemux/demuxer.c
===================================================================
--- libmpdemux/demuxer.c	(revisione 25986)
+++ libmpdemux/demuxer.c	(copia locale)
@@ -206,6 +206,7 @@
   memset(d,0,sizeof(demuxer_t));
   d->stream=stream;
   d->stream_pts = MP_NOPTS_VALUE;
+  d->reference_clock = MP_NOPTS_VALUE;
   d->movi_start=stream->start_pos;
   d->movi_end=stream->end_pos;
   d->seekable=1;
@@ -418,6 +419,12 @@
   while(1){
     if(ds->packs){
       demux_packet_t *p=ds->first;
+      if(demux->reference_clock != MP_NOPTS_VALUE) {
+        if((p->pts != MP_NOPTS_VALUE) && (p->pts > demux->reference_clock) && (ds->packs < MAX_PACKS)) {
+            if(demux_fill_buffer(demux,ds))
+              continue;
+        }
+      }
       // copy useful data:
       ds->buffer=p->buffer;
       ds->buffer_pos=0;
Index: libmpdemux/demuxer.h
===================================================================
--- libmpdemux/demuxer.h	(revisione 25986)
+++ libmpdemux/demuxer.h	(copia locale)
@@ -194,6 +194,7 @@
   off_t movi_end;
   stream_t *stream;
   double stream_pts;       // current stream pts, if applicable (e.g. dvd)
+  double reference_clock;
   char *filename; ///< Needed by avs_check_file
   int synced;  // stream synced (used by mpeg)
   int type;    // demuxer type: mpeg PS, mpeg ES, avi, avi-ni, avi-nini, asf