Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] Yet another patch for the "video data stream broken" error



This is the patch to VDR 1.3.10 I'm using to attack my "video data
stream broken" error when I start a recording.

What does it change?

- Handles frontend events asynchronously
I changed cDvbTuner::Action() to use poll() to be able to process FE
events immediately when they happen. This eliminates the fixed interval
polling in cDvbTuner::Action().

- Makes lock detection more robust
The original lock detection interpreted the shortest FE_HAS_LOCK event
as a valid lock. During my tests I observed short FE_HAS_LOCK events on
channels which can not lock. I see this when VDR is doing its scan and
tries to tune to channel 0 (what does that mean BTW?).
FE_HAS_LOCK now must be stable at least 300ms to be accepted as a valid
lock.

- Leaves cDvbDevice::SetChannelDevice() with return code false when
tuning was not successful.
Why should we do anything when we have enabled
WAIT_FOR_LOCK_AFTER_TUNING and get no lock?

This patch solves or at least improves my variant of the "video data
stream broken" problem. I got this error only at the beginning of a
recording. This problem has now disappeared for me, or at least did not
happen again since I'm using the patch.

What does it miss?

It does not handle the loss of lock in an already locked state, but the
original did not do this either, and I don't know if VDR is prepared to
react to such an event in a friendly way (I call emergency exits
unfriedly). It would be easy to add to cDvbTuner::Action() and I'll test
it later.

Some remarks:

- I have left the original cDvbTuner::Action() in the source. You may
comment out the line
#define USE_ALTERNATE_CDVBTUNER_ACTION
if you want to use the original version.

- There is the line
#define EXTENDED_DEBUGGING_OUTPUT
which enables a lot of additional debugging output. You may comment this
line out if you don't want to see this.

- The patch does not include the additional changes to dvbdevice.c
posted on the list. This is by reason. I wanted to change one thing
after the other.

Please test. Feedback extremely welcome.

Wolfgang



--- dvbdevice-orig.c	2004-07-31 10:05:42.000000000 +0200
+++ dvbdevice.c	2004-07-31 10:16:40.000000000 +0200
@@ -35,8 +35,16 @@
 
 #define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
 #define DO_MULTIPLE_RECORDINGS 1
-//#define WAIT_FOR_LOCK_AFTER_TUNING 1
+#define WAIT_FOR_LOCK_AFTER_TUNING 1
 
+#define USE_ALTERNATE_CDVBTUNER_ACTION
+#define EXTENDED_DEBUGGING_OUTPUT
+#ifdef EXTENDED_DEBUGGING_OUTPUT
+#define DSYSLOG(a...) dsyslog(a)
+#else
+#define DSYSLOG(a...)
+#endif
+ 
 #define DEV_VIDEO         "/dev/video"
 #define DEV_DVB_ADAPTER   "/dev/dvb/adapter"
 #define DEV_DVB_OSD       "osd"
@@ -248,6 +256,100 @@
   return true;
 }
 
+#ifdef USE_ALTERNATE_CDVBTUNER_ACTION
+void cDvbTuner::Action(void)
+{
+#ifdef EXTENDED_DEBUGGING_OUTPUT
+  int last;
+  last = time_ms ();
+#endif
+  active = true;
+  int lockcount = 0;
+  while (active) {
+        cMutexLock MutexLock(&mutex);
+        if (tunerStatus == tsSet)
+           tunerStatus = SetFrontend() ? tsTuned : tsIdle;
+
+        bool fast = (tunerStatus == tsTuned) || (ciHandler && (time(NULL) - startTime < 20));
+        if (tunerStatus != tsIdle) {
+           dvb_frontend_event event;
+	   struct pollfd pd;
+	   pd.fd = fd_frontend;
+	   pd.events = POLLIN | POLLPRI;
+	   int pr;
+	   /* poll call */
+	   pr = poll (&pd, 1, fast ? 100 : 1000);
+	   if (pr == 1) {
+	      if (ioctl(fd_frontend, FE_GET_EVENT, &event) == 0) {
+#ifdef EXTENDED_DEBUGGING_OUTPUT
+		 int now = time_ms ();
+		 dsyslog ("Event on frontend %d (channel \"%s\"): %02x dt =%8d ms", 
+			  cardIndex, channel.Name(), event.status, now - last);
+		 last = now;
+#endif
+		 if (event.status & FE_REINIT) {
+		    tunerStatus = tsSet;
+		    esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex);
+		    continue;
+                 }
+#ifdef EXTENDED_DEBUGGING_OUTPUT
+		 if (event.status & FE_HAS_LOCK)
+		    dsyslog ("Frontend %d (channel \"%s\") first lock", cardIndex, channel.Name());
+#endif
+		 lockcount = 0;
+              }
+           }
+	   else {
+	      if (pr == 0) {
+		 fe_status_t status = fe_status_t(0);
+		 CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
+#ifdef EXTENDED_DEBUGGING_OUTPUT
+		 int now = time_ms ();
+#endif
+		 if (status & FE_HAS_LOCK) {
+		    if (tunerStatus != tsLocked) {
+		       lockcount++;
+		       if (lockcount == 3) { 
+			  tunerStatus = tsLocked;
+#ifdef EXTENDED_DEBUGGING_OUTPUT
+			  dsyslog ("Frontend %d (channel \"%s\") locked after %d ms ", 
+				   cardIndex, channel.Name(), now - last);
+			  last = now;
+#endif
+		       }
+		    }
+		 }
+		 else {
+		    lockcount = 0;  // Paranoia. Should be caught by event
+		 }
+	      }
+	   }
+	}
+	  
+        if (ciHandler) {
+           if (ciHandler->Process() && useCa) {
+              if (tunerStatus == tsLocked) {
+                 for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
+                     cCiCaPmt CaPmt(channel.Source(), channel.Transponder(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
+                     if (CaPmt.Valid()) {
+                        CaPmt.AddPid(channel.Vpid(), 2);
+                        CaPmt.AddPid(channel.Apid1(), 4);
+                        CaPmt.AddPid(channel.Apid2(), 4);
+                        CaPmt.AddPid(channel.Dpid1(), 0);
+                        if (ciHandler->SetCaPmt(CaPmt, Slot)) {
+                           tunerStatus = tsCam;
+                           startTime = 0;
+                           }
+                        }
+                     }
+                 }
+              }
+           else if (tunerStatus > tsLocked)
+              tunerStatus = tsLocked;
+           }
+        }
+}
+#else
 void cDvbTuner::Action(void)
 {
   active = true;
@@ -296,6 +398,7 @@
         newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
         }
 }
+#endif
 
 // --- cDvbDevice ------------------------------------------------------------
 
@@ -578,6 +681,7 @@
 bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
 {
   if (Handle->pid) {
+     DSYSLOG ("SetPid: Setting pid %d (type %d) On = %d", Handle->pid, Type, On);
      dmx_pes_filter_params pesFilterParams;
      memset(&pesFilterParams, 0, sizeof(pesFilterParams));
      if (On) {
@@ -709,6 +813,7 @@
 
 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 {
+  DSYSLOG ("SetChannelDevice: channel %d, LiveView=%d", Channel->Number(), LiveView);
   bool IsEncrypted = Channel->Ca() > CACONFBASE && !ciHandler; // only LL-firmware can do non-live CA channels
 
   bool DoTune = !dvbTuner->IsTunedTo(Channel);
@@ -754,6 +859,10 @@
   time_t t0 = time(NULL);
   while (!dvbTuner->Locked() && time(NULL) - t0 < 5)
         usleep(100);
+  if (!dvbTuner->Locked()){
+    esyslog("ERROR: failed to tune to channel %d \"%s\"", Channel->Number(), Channel->Name());
+    return false;
+  }
 #endif
   // PID settings:
 

Home | Main Index | Thread Index