Hi,

the motivation for this patch was to speed up zapping channels when
using vdr-xine, i. e. to shorten the time from pressing the remote
button till audio and video appear.

FF card users may only see the effect of this patch when the FF card is
running in transfer mode.

The idea is to not wait for the first I frame in transfer mode. Although
output devices "can't" decode any frames before the first I frame, the
contained PTS in the PES packets allows the device to synchronize audio
and video even before the first video frame appears on screen.

Another issue which is addressed by this patch is that audio packets
were not delivered to the device immediately after switching the
channel, so the above change didn't have any effect. Calling
EnsureAudioTrack() fixes this.

How much speed up can be expected? Well, it varies from zap to zap as it
depends on a couple of parameters like the offset of audio and video
PTS, whether a PTS is available per frame, the number of frames till the
next I frame arrives, etc. But a speed up should be noticeable.

BTW: Testers of plugin ** should comment out the following line in
cTSBuffer::Get() in file device.c, like that:

//        if(!device->***) device->***=new c***;

This change is highly recommended if you experience buffer overflows
while switching channels, though they are not related to the sync early
patch.

Bye.
-- 
Dipl.-Inform. (FH) Reinhard Nissl
mailto:[EMAIL PROTECTED]
diff -Nurp ../vdr-1.4.6-1-orig/device.c ./device.c
--- ../vdr-1.4.6-1-orig/device.c	2006-09-03 12:13:25.000000000 +0200
+++ ./device.c	2007-05-06 21:22:52.000000000 +0200
@@ -691,7 +691,7 @@ eSetChannelResult cDevice::SetChannel(co
            for (int i = 0; i < MAXDPIDS; i++)
                SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
            }
-        if (!NeedsTransferMode)
+        if (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)
            EnsureAudioTrack(true);
         }
      cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull
diff -Nurp ../vdr-1.4.6-1-orig/remux.c ./remux.c
--- ../vdr-1.4.6-1-orig/remux.c	2006-12-01 15:46:25.000000000 +0100
+++ ./remux.c	2007-05-06 21:22:52.000000000 +0200
@@ -1853,12 +1853,13 @@ void cTS2PES::ts_to_pes(const uint8_t *B
 
 #define RESULTBUFFERSIZE KILOBYTE(256)
 
-cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure)
+cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly)
 {
   exitOnFailure = ExitOnFailure;
   isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
   numUPTerrors = 0;
   synced = false;
+  syncEarly = SyncEarly;
   skipped = 0;
   numTracks = 0;
   resultSkipped = 0;
@@ -2062,12 +2063,14 @@ uchar *cRemux::Get(int &Count, uchar *Pi
                         cThread::EmergencyExit(true);
                      }
                   else if (!synced) {
-                     if (pt == I_FRAME) {
+                     if (pt == I_FRAME || syncEarly) {
                         if (PictureType)
                            *PictureType = pt;
                         resultSkipped = i; // will drop everything before this position
-                        SetBrokenLink(data + i, l);
                         synced = true;
+                        if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink()
+                           SetBrokenLink(data + i, l);
+else fprintf(stderr, "video: synced early\n");
                         }
                      }
                   else if (Count)
@@ -2080,12 +2083,13 @@ uchar *cRemux::Get(int &Count, uchar *Pi
                l = GetPacketLength(data, resultCount, i);
                if (l < 0)
                   return resultData;
-               if (isRadio) {
+               if (isRadio || !synced && syncEarly) {
                   if (!synced) {
-                     if (PictureType)
+                     if (PictureType && isRadio)
                         *PictureType = I_FRAME;
                      resultSkipped = i; // will drop everything before this position
                      synced = true;
+if (!isRadio) fprintf(stderr, "audio: synced early\n");
                      }
                   else if (Count)
                      return resultData;
diff -Nurp ../vdr-1.4.6-1-orig/remux.h ./remux.h
--- ../vdr-1.4.6-1-orig/remux.h	2006-03-25 13:27:30.000000000 +0100
+++ ./remux.h	2007-05-06 21:22:52.000000000 +0200
@@ -40,6 +40,7 @@ private:
   bool isRadio;
   int numUPTerrors;
   bool synced;
+  bool syncEarly;
   int skipped;
   cTS2PES *ts2pes[MAXTRACKS];
   int numTracks;
@@ -47,12 +48,13 @@ private:
   int resultSkipped;
   int GetPid(const uchar *Data);
 public:
-  cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
+  cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false);
        ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while
        ///< APids, DPids and SPids are pointers to zero terminated lists of audio,
        ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such
        ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency
-       ///< exit" in case of problems with the data stream.
+       ///< exit" in case of problems with the data stream. SyncEarly causes cRemux
+       ///< to sync as soon as a video or audio frame is seen.
   ~cRemux();
   void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); }
        ///< By default cRemux assumes that Put() and Get() are called from different
diff -Nurp ../vdr-1.4.6-1-orig/transfer.c ./transfer.c
--- ../vdr-1.4.6-1-orig/transfer.c	2006-01-29 18:24:39.000000000 +0100
+++ ./transfer.c	2007-05-06 21:23:35.000000000 +0200
@@ -19,7 +19,7 @@ cTransfer::cTransfer(int VPid, const int
 ,cThread("transfer")
 {
   ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
-  remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids);
+  remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, true);
 }
 
 cTransfer::~cTransfer()
diff -Nurp ../vdr-1.5.2-orig/device.c ./device.c
--- ../vdr-1.5.2-orig/device.c	2007-01-13 13:05:00.000000000 +0100
+++ ./device.c	2007-05-06 21:13:58.000000000 +0200
@@ -735,7 +735,7 @@ eSetChannelResult cDevice::SetChannel(co
            for (int i = 0; i < MAXDPIDS; i++)
                SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
            }
-        if (!NeedsTransferMode)
+        if (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)
            EnsureAudioTrack(true);
         }
      cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull
diff -Nurp ../vdr-1.5.2-orig/remux.c ./remux.c
--- ../vdr-1.5.2-orig/remux.c	2007-02-24 17:36:10.000000000 +0100
+++ ./remux.c	2007-05-06 21:13:58.000000000 +0200
@@ -1853,12 +1853,13 @@ void cTS2PES::ts_to_pes(const uint8_t *B
 
 #define RESULTBUFFERSIZE KILOBYTE(256)
 
-cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure)
+cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly)
 {
   exitOnFailure = ExitOnFailure;
   isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
   numUPTerrors = 0;
   synced = false;
+  syncEarly = SyncEarly;
   skipped = 0;
   numTracks = 0;
   resultSkipped = 0;
@@ -2062,12 +2063,14 @@ uchar *cRemux::Get(int &Count, uchar *Pi
                         ShutdownHandler.RequestEmergencyExit();
                      }
                   else if (!synced) {
-                     if (pt == I_FRAME) {
+                     if (pt == I_FRAME || syncEarly) {
                         if (PictureType)
                            *PictureType = pt;
                         resultSkipped = i; // will drop everything before this position
-                        SetBrokenLink(data + i, l);
                         synced = true;
+                        if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink()
+                           SetBrokenLink(data + i, l);
+else fprintf(stderr, "video: synced early\n");
                         }
                      }
                   else if (Count)
@@ -2080,12 +2083,13 @@ uchar *cRemux::Get(int &Count, uchar *Pi
                l = GetPacketLength(data, resultCount, i);
                if (l < 0)
                   return resultData;
-               if (isRadio) {
+               if (isRadio || !synced && syncEarly) {
                   if (!synced) {
-                     if (PictureType)
+                     if (PictureType && isRadio)
                         *PictureType = I_FRAME;
                      resultSkipped = i; // will drop everything before this position
                      synced = true;
+if (!isRadio) fprintf(stderr, "audio: synced early\n");
                      }
                   else if (Count)
                      return resultData;
diff -Nurp ../vdr-1.5.2-orig/remux.h ./remux.h
--- ../vdr-1.5.2-orig/remux.h	2006-03-25 13:27:30.000000000 +0100
+++ ./remux.h	2007-05-06 21:13:58.000000000 +0200
@@ -40,6 +40,7 @@ private:
   bool isRadio;
   int numUPTerrors;
   bool synced;
+  bool syncEarly;
   int skipped;
   cTS2PES *ts2pes[MAXTRACKS];
   int numTracks;
@@ -47,12 +48,13 @@ private:
   int resultSkipped;
   int GetPid(const uchar *Data);
 public:
-  cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
+  cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false);
        ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while
        ///< APids, DPids and SPids are pointers to zero terminated lists of audio,
        ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such
        ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency
-       ///< exit" in case of problems with the data stream.
+       ///< exit" in case of problems with the data stream. SyncEarly causes cRemux
+       ///< to sync as soon as a video or audio frame is seen.
   ~cRemux();
   void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); }
        ///< By default cRemux assumes that Put() and Get() are called from different
diff -Nurp ../vdr-1.5.2-orig/transfer.c ./transfer.c
--- ../vdr-1.5.2-orig/transfer.c	2007-01-05 11:45:28.000000000 +0100
+++ ./transfer.c	2007-05-06 21:14:39.000000000 +0200
@@ -19,7 +19,7 @@ cTransfer::cTransfer(tChannelID ChannelI
 ,cThread("transfer")
 {
   ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
-  remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids);
+  remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, true);
 }
 
 cTransfer::~cTransfer()
_______________________________________________
vdr mailing list
vdr@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr

Reply via email to