Explaining VPS

Message ID 4493E497.8050301@cadsoft.de
State New
Headers

Commit Message

Klaus Schmidinger June 17, 2006, 11:16 a.m. UTC
  Klaus Schmidinger wrote:
> Suur Karu wrote:
>> Hi, all!
>> Please explain me how VPS works in VDR?
>> I reside in GMT+2 (+3h in summertime) timezone and
>> when watching for example ZDF EPG shows correct time, but
>> VPS reports +1h. Is it transmitted in localtime?
>> Example:
>> EPG: 06.06.2006 21:15-22:00 (45 min)
>> VPS: 06.06 20:14
>> and as result +1:01
>>
>> Is it correct?
> 
> The "Programme Identification Label" (PIL) is the "first
> published start time of a certain event", and it is in local
> time. So if you're not in the same time zone as the broadcast
> station, there's a problem.
> 
> Maybe we also need to take into account the "local time offset descriptor"
> to find out the actual time offset of the broadcast station, but
> IIRC that descriptor wasn't broadcast back when I started
> implementing VPS. I'll take a look at this...

After some testing it appears like most broadcasters do send the
TOT data. This one also carries the current time in UTC, and since
the TOT is CRC32 protected, it would even have an advantage over
the TDT, which might contain garbage without being noticed (that's
why VDR's cTDT uses 'lastDiff' in an attempt to detect invalid
time data). However, some broadcasters only send TDT, so we would
probably have to parse both of them.

So switching from TDT to TOT would have two advantages: having the
current time in a CRC32 protected way, plus giving us information
about the broadcaster's time zone. Unfortunately the time zone
information is not given directly, but rather as a "current offset
from UTC", thus also including any DST (daylight saving time).
Fortunately, though, it contains both the current and the next
offset (i.e. the one for DST and the one without DST), so taking
the smaller one of these should give us the actual time zone.

The attached patch adds parsing the TPT to VDR/eit.c and writes
some debug output to the console. For the German RTL channels this
looks like this:

TDT Sat Jun 17 11:55:18 2006
TOT Sat Jun 17 11:55:18 2006
58
DEU
0
0
200
Sun Oct 29 02:00:00 2006
100
AUT
0
0
200
Sun Oct 29 02:00:00 2006
100
CHE
0
0
200
Sun Oct 29 02:00:00 2006
100

Apparently the TOT can contain information for various time zones,
so I'm not quite sure as to how exactly this can be used in case
the entries would lead to different results.

Note that the attached patch is just for investigating the TOT.
It does not add any functionality, and it turns off setting the
system time. So don't use it in a production system unless you
know what you are doing. I'm just posting it in case somebody is
interested.

The remaining problem is that the time zone information needs
to be assigned to the individual channels, so that it is available
when an EPG event with VPS information is detected. However, the
TOT's repeat frequency varies greatly between broadcasters. Some
repeat it every second, while others send it only twice per minute.
This means that EPG events with VPS information can only be processed
correctly after the TOT has been seen - which can take quite a while.

Anyway, since this would require some incompatible changes (channels
would need to store their time zone), I'm afraid I can't make changes
here in version 1.4. I'll see what I can do in version 1.5.


It's a real pitty that the authors of the DVB standard have totally
messed up the Programme Identification Label. Instead of making this
a sequence of digits, they really should have made this a "time in UTC".
Then we wouldn't have this problem...

Klaus
  

Patch

--- eit.c	2006/05/25 14:35:19	1.118
+++ eit.c	2006/06/17 11:02:32
@@ -282,6 +282,8 @@ 
 :SI::TDT(Data, false)
 {
   CheckParse();
+  fprintf(stderr, "TDT %s\n", *TimeToString(getTime()));//XXX
+  return;//XXX
 
   time_t sattim = getTime();
   time_t loctim = time(NULL);
@@ -300,6 +302,47 @@ 
      }
 }
 
+// --- cTOT ------------------------------------------------------------------
+
+class cTOT : public SI::TOT {
+public:
+  cTOT(const u_char *Data);
+  };
+
+cTOT::cTOT(const u_char *Data)
+:SI::TOT(Data, false)
+{
+  if (!CheckCRCAndParse())
+     return;
+  fprintf(stderr, "TOT %s\n", *TimeToString(getTime()));//XXX
+  SI::Descriptor *d;
+  for (SI::Loop::Iterator it; (d = descriptorLoop.getNext(it)); ) {
+      fprintf(stderr, "%02X\n", d->getDescriptorTag());//XXX
+      switch (d->getDescriptorTag()) {
+        case SI::LocalTimeOffsetDescriptorTag: {
+             SI::LocalTimeOffsetDescriptor *ltod = (SI::LocalTimeOffsetDescriptor *)d;
+             SI::LocalTimeOffsetDescriptor::LocalTimeOffset lto;
+             for (SI::Loop::Iterator it2; ltod->localTimeOffsetLoop.getNext(lto, it2); ) {
+                 fprintf(stderr, "%s\n", lto.countryCode);//XXX
+                 fprintf(stderr, "%d\n", lto.getCountryId());//XXX
+                 fprintf(stderr, "%d\n", lto.getLocalTimeOffsetPolarity());//XXX
+                 fprintf(stderr, "%d\n", BCD2INT(lto.getLocalTimeOffset()));//XXX
+                 fprintf(stderr, "%s\n", *TimeToString(lto.getTimeOfChange()));//XXX
+                 fprintf(stderr, "%d\n", BCD2INT(lto.getNextTimeOffset()));//XXX
+                 int pol = lto.getLocalTimeOffsetPolarity() ? -1 : 1;
+                 int lto1 = BCD2INT(lto.getLocalTimeOffset());
+                 int lto2 = BCD2INT(lto.getNextTimeOffset());
+                 lto1 = pol * (lto1 / 100 * 60 + lto1 % 100) * 60;//XXX cTimer::TimeToInt() -> tools.c
+                 lto2 = pol * (lto2 / 100 * 60 + lto2 % 100) * 60;
+                 fprintf(stderr, "==> Offset from UTC = %d\n", min(lto1, lto2));//XXX
+                 }
+             }
+        default: ;
+        }
+      delete d;
+      }
+}
+
 // --- cEitFilter ------------------------------------------------------------
 
 cEitFilter::cEitFilter(void)
@@ -308,6 +351,7 @@ 
   Set(0x12, 0x50, 0xF0);  // event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
   Set(0x12, 0x60, 0xF0);  // event info, other  TS, schedule(0x60)/schedule for future days(0x6X)
   Set(0x14, 0x70);        // TDT
+  Set(0x14, 0x73);        // TOT//XXX
 }
 
 void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
@@ -331,7 +375,11 @@ 
          }
          break;
     case 0x14: {
-         if (Setup.SetSystemTime && Setup.TimeTransponder && ISTRANSPONDER(Transponder(), Setup.TimeTransponder))
+         if (Tid == 0x73) {//XXX
+            cTOT TOT(Data);
+            }
+         else//XXX
+//XXX         if (Setup.SetSystemTime && Setup.TimeTransponder && ISTRANSPONDER(Transponder(), Setup.TimeTransponder))
             cTDT TDT(Data);
          }
          break;