support patch for media-plugins/vdr-ttxtsubs
rebased for vdr-2.6.1

fixing segfault, reported on IRC #gentoo-vdr & vdr-portal.de
https://www.vdr-portal.de/forum/index.php?thread/132017-videotextuntertitel-f%C3%BCr-vdr-2-4-0/&postID=1306478#post1306478

Signed-off-by: Joerg Bornkessel <hd_brummy@gentoo.org> ( 2021 Feb 14 )
diff -Naur vdr-2.6.1.orig/MANUAL vdr-2.6.1/MANUAL
--- vdr-2.6.1.orig/MANUAL	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/MANUAL	2022-06-20 01:17:40.241599868 +0200
@@ -963,6 +963,9 @@
                          background transparency. By default the values as broadcast
                          are used.
 
+  Enable teletext support = yes
+                         If set to 'yes', enables teletext subtitles.
+
   LNB:
 
   Use DiSEqC = no        Generally turns DiSEqC support on or off.
diff -Naur vdr-2.6.1.orig/Makefile vdr-2.6.1/Makefile
--- vdr-2.6.1.orig/Makefile	2022-06-20 01:16:19.139838587 +0200
+++ vdr-2.6.1/Makefile	2022-06-20 01:17:40.241599868 +0200
@@ -94,6 +94,8 @@
        skinclassic.o skinlcars.o skins.o skinsttng.o sourceparams.o sources.o spu.o status.o svdrp.o themes.o thread.o\
        timers.o tools.o transfer.o vdr.o videodir.o
 
+OBJS += vdrttxtsubshooks.o
+
 DEFINES  += $(CDEFINES)
 INCLUDES += $(CINCLUDES)
 
diff -Naur vdr-2.6.1.orig/channels.c vdr-2.6.1/channels.c
--- vdr-2.6.1.orig/channels.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/channels.c	2022-06-20 01:17:40.241599868 +0200
@@ -434,6 +434,27 @@
   return Modified;
 }
 
+bool cChannel::SetTeletextSubtitlePages(tTeletextSubtitlePage pages[], int numberOfPages)
+{
+  int mod = CHANNELMOD_NONE;
+  LOCK_CHANNELS_WRITE;
+  if (totalTtxtSubtitlePages != (fixedTtxtSubtitlePages + numberOfPages))
+     mod |= CHANNELMOD_PIDS;
+  totalTtxtSubtitlePages = fixedTtxtSubtitlePages;
+  for (int i = 0; (i < numberOfPages) && (totalTtxtSubtitlePages < MAXTXTPAGES); i++) {
+      if (teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine != pages[i].ttxtMagazine ||
+          teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage != pages[i].ttxtPage ||
+          teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType != pages[i].ttxtType ||
+          strcmp(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, pages[i].ttxtLanguage)) {
+         mod |= CHANNELMOD_PIDS;
+         teletextSubtitlePages[totalTtxtSubtitlePages] = pages[i];
+         }
+      totalTtxtSubtitlePages++;
+      }
+  modification |= mod;
+  return true;
+}
+
 void cChannel::SetSeen(void)
 {
   seen = time(NULL);
@@ -588,10 +609,17 @@
         q += IntArrayToString(q, Channel->dpids, 10, Channel->dlangs, Channel->dtypes);
         }
      *q = 0;
-     const int TBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia and tpid
+     const int TBufferSize = (MAXTXTPAGES * MAXSPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia and tpid
      char tpidbuf[TBufferSize];
      q = tpidbuf;
      q += snprintf(q, sizeof(tpidbuf), "%d", Channel->tpid);
+     if (Channel->fixedTtxtSubtitlePages > 0) {
+        *q++ = '+';
+        for (int i = 0; i < Channel->fixedTtxtSubtitlePages; ++i) {
+            tTeletextSubtitlePage page = Channel->teletextSubtitlePages[i];
+            q += snprintf(q, sizeof(tpidbuf) - (q - tpidbuf), "%d=%s", page.PageNumber(), page.ttxtLanguage);
+            }
+        }
      if (Channel->spids[0]) {
         *q++ = ';';
         q += IntArrayToString(q, Channel->spids, 10, Channel->slangs);
@@ -763,6 +791,32 @@
                     }
               spids[NumSpids] = 0;
               }
+           fixedTtxtSubtitlePages = 0;
+           if ((p = strchr(tpidbuf, '+')) != NULL) {
+              *p++ = 0;
+              char *q;
+              char *strtok_next;
+              while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
+                    if (fixedTtxtSubtitlePages < MAXTXTPAGES) {
+                       int page;
+                       char *l = strchr(q, '=');
+                       if (l)
+                          *l++ = 0;
+                       if (sscanf(q, "%d", &page) == 1) {
+                          teletextSubtitlePages[fixedTtxtSubtitlePages] = tTeletextSubtitlePage(page);
+                          if (l)
+                             strn0cpy(teletextSubtitlePages[fixedTtxtSubtitlePages].ttxtLanguage, l, MAXLANGCODE2);
+                          fixedTtxtSubtitlePages++;
+                          }
+                       else
+                          esyslog("ERROR: invalid Teletext page!"); // no need to set ok to 'false'
+                       }
+                    else
+                       esyslog("ERROR: too many Teletext pages!"); // no need to set ok to 'false'
+                    p = NULL;
+                    }
+              totalTtxtSubtitlePages = fixedTtxtSubtitlePages;
+              }
            if (sscanf(tpidbuf, "%d", &tpid) != 1)
               return false;
            if (caidbuf) {
diff -Naur vdr-2.6.1.orig/channels.h vdr-2.6.1/channels.h
--- vdr-2.6.1.orig/channels.h	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/channels.h	2022-06-20 01:17:40.241599868 +0200
@@ -32,6 +32,7 @@
 #define MAXDPIDS 16 // dolby (AC3 + DTS)
 #define MAXSPIDS 32 // subtitles
 #define MAXCAIDS 12 // conditional access
+#define MAXTXTPAGES 8 // teletext pages
 
 #define MAXLANGCODE1 4 // a 3 letter language code, zero terminated
 #define MAXLANGCODE2 8 // up to two 3 letter language codes, separated by '+' and zero terminated
@@ -68,6 +69,16 @@
   static const tChannelID InvalidID;
   };
 
+struct tTeletextSubtitlePage {
+  tTeletextSubtitlePage(void) { ttxtPage = ttxtMagazine = 0; ttxtType = 0x02; strcpy(ttxtLanguage, "und"); }
+  tTeletextSubtitlePage(int page) { ttxtMagazine = (page / 100) & 0x7; ttxtPage = (((page % 100) / 10) << 4) + (page % 10); ttxtType = 0x02; strcpy(ttxtLanguage, "und"); }
+  char ttxtLanguage[MAXLANGCODE1];
+  uchar ttxtPage;
+  uchar ttxtMagazine;
+  uchar ttxtType;
+  int PageNumber(void) const { return BCDCHARTOINT(ttxtMagazine) * 100 + BCDCHARTOINT(ttxtPage); }
+  };
+
 class cChannel;
 
 class cLinkChannel : public cListObject {
@@ -114,6 +125,9 @@
   uint16_t compositionPageIds[MAXSPIDS];
   uint16_t ancillaryPageIds[MAXSPIDS];
   int tpid;
+  int fixedTtxtSubtitlePages;
+  int totalTtxtSubtitlePages;
+  tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES];
   int caids[MAXCAIDS + 1]; // list is zero-terminated
   int nid;
   int tid;
@@ -168,6 +182,8 @@
   uint16_t CompositionPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? compositionPageIds[i] : uint16_t(0); }
   uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); }
   int Tpid(void) const { return tpid; }
+  const tTeletextSubtitlePage *TeletextSubtitlePages() const { return teletextSubtitlePages; }
+  int TotalTeletextSubtitlePages() const { return totalTtxtSubtitlePages; }
   const int *Caids(void) const { return caids; }
   int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
   int Nid(void) const { return nid; }
@@ -198,6 +214,7 @@
   bool SetName(const char *Name, const char *ShortName, const char *Provider);
   bool SetPortalName(const char *PortalName);
   bool SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid);
+  bool SetTeletextSubtitlePages(tTeletextSubtitlePage pages[], int numberOfPages);
   bool SetCaIds(const int *CaIds); // list must be zero-terminated
   bool SetCaDescriptors(int Level);
   bool SetLinkChannels(cLinkChannels *LinkChannels);
diff -Naur vdr-2.6.1.orig/ci.c vdr-2.6.1/ci.c
--- vdr-2.6.1.orig/ci.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/ci.c	2022-06-20 01:17:40.241599868 +0200
@@ -2732,6 +2732,8 @@
          AddPid(Channel->Sid(), *Dpid, STREAM_TYPE_PRIVATE);
      for (const int *Spid = Channel->Spids(); *Spid; Spid++)
          AddPid(Channel->Sid(), *Spid, STREAM_TYPE_PRIVATE);
+     if (Channel->Tpid() && Setup.SupportTeletext)
+        AddPid(Channel->Sid(), Channel->Tpid(), STREAM_TYPE_PRIVATE);
      }
 }
 
@@ -2755,6 +2757,9 @@
          CaPmt.AddPid(*Dpid, STREAM_TYPE_PRIVATE);
      for (const int *Spid = Channel->Spids(); *Spid; Spid++)
          CaPmt.AddPid(*Spid, STREAM_TYPE_PRIVATE);
+     if (Channel->Tpid() && Setup.SupportTeletext) {
+        CaPmt.AddPid(Channel->Tpid(), STREAM_TYPE_PRIVATE);
+        }
      if (MtdMapper)
         CaPmt.MtdMapPids(MtdMapper);
      cas->SendPMT(&CaPmt);
diff -Naur vdr-2.6.1.orig/config.c vdr-2.6.1/config.c
--- vdr-2.6.1.orig/config.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/config.c	2022-06-20 01:17:40.241599868 +0200
@@ -403,6 +403,7 @@
   MarginStop = 10;
   AudioLanguages[0] = -1;
   DisplaySubtitles = 0;
+  SupportTeletext = 1;
   SubtitleLanguages[0] = -1;
   SubtitleOffset = 0;
   SubtitleFgTransparency = 0;
@@ -631,6 +632,7 @@
   else if (!strcasecmp(Name, "MarginStop"))          MarginStop         = atoi(Value);
   else if (!strcasecmp(Name, "AudioLanguages"))      return ParseLanguages(Value, AudioLanguages);
   else if (!strcasecmp(Name, "DisplaySubtitles"))    DisplaySubtitles   = atoi(Value);
+  else if (!strcasecmp(Name, "SupportTeletext"))     SupportTeletext    = atoi(Value);
   else if (!strcasecmp(Name, "SubtitleLanguages"))   return ParseLanguages(Value, SubtitleLanguages);
   else if (!strcasecmp(Name, "SubtitleOffset"))      SubtitleOffset     = atoi(Value);
   else if (!strcasecmp(Name, "SubtitleFgTransparency")) SubtitleFgTransparency = atoi(Value);
@@ -763,6 +765,7 @@
   Store("MarginStop",         MarginStop);
   StoreLanguages("AudioLanguages", AudioLanguages);
   Store("DisplaySubtitles",   DisplaySubtitles);
+  Store("SupportTeletext",    SupportTeletext);
   StoreLanguages("SubtitleLanguages", SubtitleLanguages);
   Store("SubtitleOffset",     SubtitleOffset);
   Store("SubtitleFgTransparency", SubtitleFgTransparency);
diff -Naur vdr-2.6.1.orig/config.h vdr-2.6.1/config.h
--- vdr-2.6.1.orig/config.h	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/config.h	2022-06-20 01:17:40.241599868 +0200
@@ -287,6 +287,7 @@
   int MarginStart, MarginStop;
   int AudioLanguages[I18N_MAX_LANGUAGES + 1];
   int DisplaySubtitles;
+  int SupportTeletext;
   int SubtitleLanguages[I18N_MAX_LANGUAGES + 1];
   int SubtitleOffset;
   int SubtitleFgTransparency, SubtitleBgTransparency;
diff -Naur vdr-2.6.1.orig/device.c vdr-2.6.1/device.c
--- vdr-2.6.1.orig/device.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/device.c	2022-06-20 01:17:40.241599868 +0200
@@ -19,6 +19,7 @@
 #include "receiver.h"
 #include "status.h"
 #include "transfer.h"
+#include "vdrttxtsubshooks.h"
 
 // --- cLiveSubtitle ---------------------------------------------------------
 
@@ -1443,6 +1444,13 @@
                   }
                break;
           case 0xBD: { // private stream 1
+               // EBU Teletext data, ETSI EN 300 472
+               // if PES data header length = 24 and data_identifier = 0x10..0x1F (EBU Data)
+               if (Data[8] == 0x24 && Data[45] >= 0x10 && Data[45] < 0x20) {
+                  cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData((uint8_t*)Data, Length);
+                  break;
+                  }
+
                int PayloadOffset = Data[8] + 9;
 
                // Compatibility mode for old subtitles plugin:
@@ -1601,6 +1609,7 @@
      tsToPesVideo.Reset();
      tsToPesAudio.Reset();
      tsToPesSubtitle.Reset();
+     tsToPesTeletext.Reset();
      }
   else if (Length < TS_SIZE) {
      esyslog("ERROR: skipped %d bytes of TS fragment", Length);
@@ -1640,6 +1649,17 @@
                     if (!VideoOnly || HasIBPTrickSpeed())
                        PlayTsSubtitle(Data, TS_SIZE);
                     }
+                 else if (Pid == patPmtParser.Tpid()) {
+                    if (!VideoOnly || HasIBPTrickSpeed()) {
+                       int l;
+                       tsToPesTeletext.PutTs(Data, Length);
+                       if (const uchar *p = tsToPesTeletext.GetPes(l)) {
+                          if ((l > 45) && (p[0] == 0x00) && (p[1] == 0x00) && (p[2] == 0x01) && (p[3] == 0xbd) && (p[8] == 0x24) && (p[45] >= 0x10) && (p[45] < 0x20))
+                             cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData((uchar *)p, l, false, patPmtParser.TeletextSubtitlePages(), patPmtParser.TotalTeletextSubtitlePages());
+                          tsToPesTeletext.Reset();
+                          }
+                       }
+                    }
                  }
               }
            else if (Pid == patPmtParser.Ppid()) {
diff -Naur vdr-2.6.1.orig/device.h vdr-2.6.1/device.h
--- vdr-2.6.1.orig/device.h	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/device.h	2022-06-20 01:17:40.245599955 +0200
@@ -641,6 +641,7 @@
   cTsToPes tsToPesVideo;
   cTsToPes tsToPesAudio;
   cTsToPes tsToPesSubtitle;
+  cTsToPes tsToPesTeletext;
   bool isPlayingVideo;
 protected:
   const cPatPmtParser *PatPmtParser(void) const { return &patPmtParser; }
diff -Naur vdr-2.6.1.orig/menu.c vdr-2.6.1/menu.c
--- vdr-2.6.1.orig/menu.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/menu.c	2022-06-20 01:17:40.245599955 +0200
@@ -3785,6 +3785,7 @@
      Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
      Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
      }
+  Add(new cMenuEditBoolItem(tr("Setup.DVB$Enable teletext support"), &data.SupportTeletext));
 
   SetCurrent(Get(current));
   Display();
diff -Naur vdr-2.6.1.orig/pat.c vdr-2.6.1/pat.c
--- vdr-2.6.1.orig/pat.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/pat.c	2022-06-20 01:17:40.245599955 +0200
@@ -12,6 +12,7 @@
 #include "channels.h"
 #include "libsi/section.h"
 #include "libsi/descriptor.h"
+#include "vdrttxtsubshooks.h"
 
 #define PMT_SCAN_TIMEOUT  1000 // ms
 
@@ -632,6 +633,8 @@
         char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
         char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
         int Tpid = 0;
+        tTeletextSubtitlePage TeletextSubtitlePages[MAXTXTPAGES];
+        int NumTPages = 0;
         int NumApids = 0;
         int NumDpids = 0;
         int NumSpids = 0;
@@ -724,8 +727,21 @@
                                     NumSpids++;
                                     }
                                  break;
-                            case SI::TeletextDescriptorTag:
+                            case SI::TeletextDescriptorTag: {
                                  Tpid = esPid;
+                                 SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d;
+                                 SI::TeletextDescriptor::Teletext ttxt;
+                                 for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
+                                     bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
+                                     if ((NumTPages < MAXTXTPAGES) && ttxt.languageCode[0] && isSubtitlePage) {
+                                        strn0cpy(TeletextSubtitlePages[NumTPages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1);
+                                        TeletextSubtitlePages[NumTPages].ttxtPage = ttxt.getTeletextPageNumber();
+                                        TeletextSubtitlePages[NumTPages].ttxtMagazine = ttxt.getTeletextMagazineNumber();
+                                        TeletextSubtitlePages[NumTPages].ttxtType = ttxt.getTeletextType();
+                                        NumTPages++;
+                                        }
+                                     }
+                                 }
                                  break;
                             case SI::ISO639LanguageDescriptorTag: {
                                  SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
@@ -839,6 +855,12 @@
             }
         if (Setup.UpdateChannels >= 2) {
            ChannelsModified |= Channel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
+           if (NumTPages < MAXTXTPAGES) {
+              int manualPageNumber = cVDRTtxtsubsHookListener::Hook()->ManualPageNumber(Channel);
+              if (manualPageNumber)
+                 TeletextSubtitlePages[NumTPages++] = tTeletextSubtitlePage(manualPageNumber);
+              }
+           ChannelsModified |= Channel->SetTeletextSubtitlePages(TeletextSubtitlePages, NumTPages);
            ChannelsModified |= Channel->SetCaIds(CaDescriptors->CaIds());
            ChannelsModified |= Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
            }
diff -Naur vdr-2.6.1.orig/po/ar.po vdr-2.6.1/po/ar.po
--- vdr-2.6.1.orig/po/ar.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/ar.po	2022-06-20 01:17:40.245599955 +0200
@@ -1123,6 +1123,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "شفافية الخلفية"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "الاقط"
 
diff -Naur vdr-2.6.1.orig/po/ca_ES.po vdr-2.6.1/po/ca_ES.po
--- vdr-2.6.1.orig/po/ca_ES.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/ca_ES.po	2022-06-20 01:17:40.245599955 +0200
@@ -1122,6 +1122,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparncia fons subttols"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "Configuraci de l'LNB"
 
diff -Naur vdr-2.6.1.orig/po/cs_CZ.po vdr-2.6.1/po/cs_CZ.po
--- vdr-2.6.1.orig/po/cs_CZ.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/cs_CZ.po	2022-06-20 01:17:40.245599955 +0200
@@ -1122,6 +1122,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Průhlednost pozadí titulků"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/da_DK.po vdr-2.6.1/po/da_DK.po
--- vdr-2.6.1.orig/po/da_DK.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/da_DK.po	2022-06-20 01:17:40.245599955 +0200
@@ -1119,6 +1119,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Undertekst baggrundsgennemsigtighed"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/de_DE.po vdr-2.6.1/po/de_DE.po
--- vdr-2.6.1.orig/po/de_DE.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/de_DE.po	2022-06-20 01:17:36.541519538 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Untertitel-Transparenz Hintergrund"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr "Videotext-Untersttzung aktivieren"
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/el_GR.po vdr-2.6.1/po/el_GR.po
--- vdr-2.6.1.orig/po/el_GR.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/el_GR.po	2022-06-20 01:17:40.245599955 +0200
@@ -1119,6 +1119,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr ""
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/es_ES.po vdr-2.6.1/po/es_ES.po
--- vdr-2.6.1.orig/po/es_ES.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/es_ES.po	2022-06-20 01:17:40.245599955 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparencia fondo subttulos"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/et_EE.po vdr-2.6.1/po/et_EE.po
--- vdr-2.6.1.orig/po/et_EE.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/et_EE.po	2022-06-20 01:17:40.245599955 +0200
@@ -1119,6 +1119,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Subtiitri tausta läbipaistvus"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr "Teleteksti tugi"
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/fi_FI.po vdr-2.6.1/po/fi_FI.po
--- vdr-2.6.1.orig/po/fi_FI.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/fi_FI.po	2022-06-20 01:17:40.245599955 +0200
@@ -1123,6 +1123,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Tekstityksen taustan läpinäkyvyys"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr "Salli teksti-TV-tuki"
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/fr_FR.po vdr-2.6.1/po/fr_FR.po
--- vdr-2.6.1.orig/po/fr_FR.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/fr_FR.po	2022-06-20 01:17:40.249600042 +0200
@@ -1130,6 +1130,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparence du fond des sous-titres"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/hr_HR.po vdr-2.6.1/po/hr_HR.po
--- vdr-2.6.1.orig/po/hr_HR.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/hr_HR.po	2022-06-20 01:17:40.249600042 +0200
@@ -1121,6 +1121,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparentnost pozadine titla"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/hu_HU.po vdr-2.6.1/po/hu_HU.po
--- vdr-2.6.1.orig/po/hu_HU.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/hu_HU.po	2022-06-20 01:17:40.249600042 +0200
@@ -1124,6 +1124,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Felirat hátterének transzparenciája"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/it_IT.po vdr-2.6.1/po/it_IT.po
--- vdr-2.6.1.orig/po/it_IT.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/it_IT.po	2022-06-20 01:17:40.249600042 +0200
@@ -1125,6 +1125,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Trasparenza sfondo sottotitoli"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/lt_LT.po vdr-2.6.1/po/lt_LT.po
--- vdr-2.6.1.orig/po/lt_LT.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/lt_LT.po	2022-06-20 01:17:40.249600042 +0200
@@ -1119,6 +1119,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Subtitrų fono permatomumas"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "Konverteris (LNB)"
 
diff -Naur vdr-2.6.1.orig/po/mk_MK.po vdr-2.6.1/po/mk_MK.po
--- vdr-2.6.1.orig/po/mk_MK.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/mk_MK.po	2022-06-20 01:17:40.249600042 +0200
@@ -1121,6 +1121,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Провидност на позадината на титлот"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/nl_NL.po vdr-2.6.1/po/nl_NL.po
--- vdr-2.6.1.orig/po/nl_NL.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/nl_NL.po	2022-06-20 01:17:40.249600042 +0200
@@ -1125,6 +1125,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparantie achtergrond ondertiteling"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/nn_NO.po vdr-2.6.1/po/nn_NO.po
--- vdr-2.6.1.orig/po/nn_NO.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/nn_NO.po	2022-06-20 01:17:40.249600042 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr ""
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/pl_PL.po vdr-2.6.1/po/pl_PL.po
--- vdr-2.6.1.orig/po/pl_PL.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/pl_PL.po	2022-06-20 01:17:40.249600042 +0200
@@ -1124,6 +1124,10 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Przeźrocze podtytułów: Tło"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/pt_PT.po vdr-2.6.1/po/pt_PT.po
--- vdr-2.6.1.orig/po/pt_PT.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/pt_PT.po	2022-06-20 01:17:40.249600042 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparncia de fundo das legendas"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/ro_RO.po vdr-2.6.1/po/ro_RO.po
--- vdr-2.6.1.orig/po/ro_RO.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/ro_RO.po	2022-06-20 01:17:40.249600042 +0200
@@ -1121,6 +1121,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparenţa fundalului subtitrării"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/ru_RU.po vdr-2.6.1/po/ru_RU.po
--- vdr-2.6.1.orig/po/ru_RU.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/ru_RU.po	2022-06-20 01:17:40.249600042 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Прозрачность фона субтитров"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "Конвертер"
 
diff -Naur vdr-2.6.1.orig/po/sk_SK.po vdr-2.6.1/po/sk_SK.po
--- vdr-2.6.1.orig/po/sk_SK.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/sk_SK.po	2022-06-20 01:17:40.249600042 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Priehadnos pozadia titulkov"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB (nzko umov jednotka)"
 
diff -Naur vdr-2.6.1.orig/po/sl_SI.po vdr-2.6.1/po/sl_SI.po
--- vdr-2.6.1.orig/po/sl_SI.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/sl_SI.po	2022-06-20 01:17:40.249600042 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparentnost ozadja podnapisov"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/sr_RS.po vdr-2.6.1/po/sr_RS.po
--- vdr-2.6.1.orig/po/sr_RS.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/sr_RS.po	2022-06-20 01:17:40.253600129 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Providnost pozadine titla"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/sv_SE.po vdr-2.6.1/po/sv_SE.po
--- vdr-2.6.1.orig/po/sv_SE.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/sv_SE.po	2022-06-20 01:17:40.253600129 +0200
@@ -1124,6 +1124,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Transparent bakgrund textremsa"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/tr_TR.po vdr-2.6.1/po/tr_TR.po
--- vdr-2.6.1.orig/po/tr_TR.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/tr_TR.po	2022-06-20 01:17:40.253600129 +0200
@@ -1119,6 +1119,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Altyaz arka effaflk"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "LNB"
 
diff -Naur vdr-2.6.1.orig/po/uk_UA.po vdr-2.6.1/po/uk_UA.po
--- vdr-2.6.1.orig/po/uk_UA.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/uk_UA.po	2022-06-20 01:17:40.253600129 +0200
@@ -1120,6 +1120,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "Прозорість заднього плану субтитрів"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "Конвертер"
 
diff -Naur vdr-2.6.1.orig/po/zh_CN.po vdr-2.6.1/po/zh_CN.po
--- vdr-2.6.1.orig/po/zh_CN.po	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/po/zh_CN.po	2022-06-20 01:17:40.253600129 +0200
@@ -1121,6 +1121,9 @@
 msgid "Setup.DVB$Subtitle background transparency"
 msgstr "字幕背景透明度"
 
+msgid "Setup.DVB$Enable teletext support"
+msgstr ""
+
 msgid "LNB"
 msgstr "切换器设置"
 
diff -Naur vdr-2.6.1.orig/receiver.c vdr-2.6.1/receiver.c
--- vdr-2.6.1.orig/receiver.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/receiver.c	2022-06-20 01:17:40.253600129 +0200
@@ -82,7 +82,8 @@
             (Channel->Ppid() == Channel->Vpid() || AddPid(Channel->Ppid())) &&
             AddPids(Channel->Apids()) &&
             AddPids(Channel->Dpids()) &&
-            AddPids(Channel->Spids());
+            AddPids(Channel->Spids()) &&
+            (!Setup.SupportTeletext || AddPid(Channel->Tpid()));
      }
   return true;
 }
diff -Naur vdr-2.6.1.orig/remux.c vdr-2.6.1/remux.c
--- vdr-2.6.1.orig/remux.c	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/remux.c	2022-06-20 01:17:40.253600129 +0200
@@ -429,6 +429,29 @@
   return i;
 }
 
+int cPatPmtGenerator::MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount)
+{
+  int i = 0, j = 0;
+  Target[i++] = SI::TeletextDescriptorTag;
+  int l = i;
+  Target[i++] = 0x00; // length
+  for (int n = 0; n < pageCount; n++) {
+      const char* Language = pages[n].ttxtLanguage;
+      Target[i++] = *Language++;
+      Target[i++] = *Language++;
+      Target[i++] = *Language++;
+      Target[i++] = (pages[n].ttxtType << 3) + pages[n].ttxtMagazine;
+      Target[i++] = pages[n].ttxtPage;
+      j++;
+      }
+  if (j > 0) {
+     Target[l] = j * 5; // update length
+     IncEsInfoLength(i);
+     return i;
+     }
+  return 0;
+}
+
 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
 {
   int i = 0;
@@ -516,6 +539,7 @@
   if (Channel) {
      int Vpid = Channel->Vpid();
      int Ppid = Channel->Ppid();
+     int Tpid = Channel->Tpid();
      uchar *p = buf;
      int i = 0;
      p[i++] = 0x02; // table id
@@ -548,6 +572,10 @@
          i += MakeStream(buf + i, 0x06, Channel->Spid(n));
          i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
          }
+     if (Tpid) {
+        i += MakeStream(buf + i, 0x06, Tpid);
+        i += MakeTeletextDescriptor(buf + i, Channel->TeletextSubtitlePages(), Channel->TotalTeletextSubtitlePages());
+        }
 
      int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
      buf[SectionLength] |= (sl >> 8) & 0x0F;
@@ -622,6 +650,7 @@
   pmtPids[0] = 0;
   vpid = vtype = 0;
   ppid = 0;
+  tpid = 0;
 }
 
 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
@@ -710,11 +739,13 @@
      int NumSpids = 0;
      vpid = vtype = 0;
      ppid = 0;
+     tpid = 0;
      apids[0] = 0;
      dpids[0] = 0;
      spids[0] = 0;
      atypes[0] = 0;
      dtypes[0] = 0;
+     totalTtxtSubtitlePages = 0;
      SI::PMT::Stream stream;
      for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
          dbgpatpmt("     stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
@@ -814,6 +845,28 @@
                                     spids[NumSpids] = 0;
                                     }
                                  break;
+                            case SI::TeletextDescriptorTag: {
+                                 dbgpatpmt(" teletext");
+                                 tpid = stream.getPid();
+                                 SI::TeletextDescriptor *sd = (SI::TeletextDescriptor *)d;
+                                 SI::TeletextDescriptor::Teletext ttxt;
+                                 if (totalTtxtSubtitlePages < MAXTXTPAGES) {
+                                    for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
+                                        bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
+                                        if (isSubtitlePage && ttxt.languageCode[0]) {
+                                           dbgpatpmt(" '%s:%x.%x'", ttxt.languageCode, ttxt.getTeletextMagazineNumber(), ttxt.getTeletextPageNumber());
+                                           strn0cpy(teletextSubtitlePages[totalTtxtSubtitlePages].ttxtLanguage, I18nNormalizeLanguageCode(ttxt.languageCode), MAXLANGCODE1);
+                                           teletextSubtitlePages[totalTtxtSubtitlePages].ttxtPage = ttxt.getTeletextPageNumber();
+                                           teletextSubtitlePages[totalTtxtSubtitlePages].ttxtMagazine = ttxt.getTeletextMagazineNumber();
+                                           teletextSubtitlePages[totalTtxtSubtitlePages].ttxtType = ttxt.getTeletextType();
+                                           totalTtxtSubtitlePages++;
+                                           if (totalTtxtSubtitlePages >= MAXTXTPAGES)
+                                              break;
+                                           }
+                                        }
+                                    }
+                                 }
+                                 break;
                             case SI::ISO639LanguageDescriptorTag: {
                                  SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
                                  dbgpatpmt(" '%s'", ld->languageCode);
diff -Naur vdr-2.6.1.orig/remux.h vdr-2.6.1/remux.h
--- vdr-2.6.1.orig/remux.h	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/remux.h	2022-06-20 01:17:40.253600129 +0200
@@ -313,6 +313,7 @@
   int MakeStream(uchar *Target, uchar Type, int Pid);
   int MakeAC3Descriptor(uchar *Target, uchar Type);
   int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId);
+  int MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount);
   int MakeLanguageDescriptor(uchar *Target, const char *Language);
   int MakeCRC(uchar *Target, const uchar *Data, int Length);
   void GeneratePmtPid(const cChannel *Channel);
@@ -360,6 +361,7 @@
   int vpid;
   int ppid;
   int vtype;
+  int tpid;
   int apids[MAXAPIDS + 1]; // list is zero-terminated
   int atypes[MAXAPIDS + 1]; // list is zero-terminated
   char alangs[MAXAPIDS][MAXLANGCODE2];
@@ -373,6 +375,8 @@
   uint16_t ancillaryPageIds[MAXSPIDS];
   bool updatePrimaryDevice;
   bool completed;
+  int totalTtxtSubtitlePages;
+  tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES];
 protected:
   int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; }
 public:
@@ -409,6 +413,9 @@
   int Vtype(void) const { return vtype; }
        ///< Returns the video stream type as defined by the current PMT, or 0 if no video
        ///< stream type has been detected, yet.
+  int Tpid(void) { return tpid; }
+       ///< Returns the teletext pid as defined by the current PMT, or 0 if no teletext
+       ///< pid has been detected, yet.
   bool Completed(void) { return completed; }
        ///< Returns true if the PMT has been completely parsed.
   const int *Apids(void) const { return apids; }
@@ -425,6 +432,8 @@
   uchar SubtitlingType(int i) const { return (0 <= i && i < MAXSPIDS) ? subtitlingTypes[i] : uchar(0); }
   uint16_t CompositionPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? compositionPageIds[i] : uint16_t(0); }
   uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); }
+  const tTeletextSubtitlePage *TeletextSubtitlePages() const { return teletextSubtitlePages; }
+  int TotalTeletextSubtitlePages() const { return totalTtxtSubtitlePages; }
   };
 
 // EIT Generator:
diff -Naur vdr-2.6.1.orig/vdr.5 vdr-2.6.1/vdr.5
--- vdr-2.6.1.orig/vdr.5	2022-02-02 10:56:43.000000000 +0100
+++ vdr-2.6.1/vdr.5	2022-06-20 01:17:40.253600129 +0200
@@ -249,6 +249,12 @@
 
 .B ...:201;2001=deu,2002=eng:...
 
+Manual teletext subtitling pages can be defined separated by a '+' sign.
+The pages (separated by commas) can contain language codes, delimited by a '='
+sign, as in
+
+.B ...:201+150=deu,151=fin;2001,2002:...
+
 .TP
 .B Conditional access
 A hexadecimal integer defining how this channel can be accessed:
diff -Naur vdr-2.6.1.orig/vdrttxtsubshooks.c vdr-2.6.1/vdrttxtsubshooks.c
--- vdr-2.6.1.orig/vdrttxtsubshooks.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-2.6.1/vdrttxtsubshooks.c	2022-06-20 01:17:40.253600129 +0200
@@ -0,0 +1,63 @@
+/*
+ * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder
+ * Copyright (c) 2003 - 2008 Ragnar Sundblad <ragge@nada.kth.se>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "vdrttxtsubshooks.h"
+
+// XXX Really should be a list...
+static cVDRTtxtsubsHookListener *gListener;
+
+// ------ class cVDRTtxtsubsHookProxy ------
+
+class cVDRTtxtsubsHookProxy : public cVDRTtxtsubsHookListener
+{
+ public:
+  virtual void HideOSD(void) { if(gListener) gListener->HideOSD(); };
+  virtual void ShowOSD(void) { if(gListener) gListener->ShowOSD(); };
+  virtual void PlayerTeletextData(uint8_t *p, int length, bool IsPesRecording, const struct tTeletextSubtitlePage teletextSubtitlePages[] = NULL, int pageCount = 0)
+    { if(gListener) gListener->PlayerTeletextData(p, length, IsPesRecording, teletextSubtitlePages, pageCount); };
+  virtual int ManualPageNumber(const cChannel *channel)
+    { if(gListener) return gListener->ManualPageNumber(channel); else return 0; };
+};
+
+
+// ------ class cVDRTtxtsubsHookListener ------
+
+cVDRTtxtsubsHookListener::~cVDRTtxtsubsHookListener()
+{
+  gListener = 0;
+}
+
+void cVDRTtxtsubsHookListener::HookAttach(void)
+{
+  gListener = this;
+  //printf("cVDRTtxtsubsHookListener::HookAttach\n");
+}
+
+static cVDRTtxtsubsHookProxy gProxy;
+
+cVDRTtxtsubsHookListener *cVDRTtxtsubsHookListener::Hook(void)
+{
+  return &gProxy;
+}
+
diff -Naur vdr-2.6.1.orig/vdrttxtsubshooks.h vdr-2.6.1/vdrttxtsubshooks.h
--- vdr-2.6.1.orig/vdrttxtsubshooks.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-2.6.1/vdrttxtsubshooks.h	2022-06-20 01:17:40.253600129 +0200
@@ -0,0 +1,46 @@
+/*
+ * vdr-ttxtsubs - A plugin for the Linux Video Disk Recorder
+ * Copyright (c) 2003 - 2008 Ragnar Sundblad <ragge@nada.kth.se>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __VDRTTXTSUBSHOOKS_H
+#define __VDRTTXTSUBSHOOKS_H
+
+#define TTXTSUBSVERSNUM 2
+
+class cDevice;
+class cChannel;
+struct tTeletextSubtitlePage;
+
+class cVDRTtxtsubsHookListener {
+ public:
+  cVDRTtxtsubsHookListener(void) {};
+  virtual ~cVDRTtxtsubsHookListener();
+
+  void HookAttach(void);
+
+  virtual void HideOSD(void) {};
+  virtual void ShowOSD(void) {};
+  virtual void PlayerTeletextData(uint8_t *p, int length, bool IsPesRecording = true, const struct tTeletextSubtitlePage teletextSubtitlePages[] = NULL, int pageCount = 0) {};
+  virtual int ManualPageNumber(const cChannel *channel) { return 0; };
+
+  // used by VDR to call hook listeners
+  static cVDRTtxtsubsHookListener *Hook(void);
+};
+
+#endif
