Sisyphus repository
Last update: 1 october 2023 | SRPMs: 18631 | Visits: 37756280
en ru br
ALT Linux repos
S:2.2.0-alt12
D:1.6.0-alt1
3.0: 1.3.15-alt1

Group :: Video
RPM: vdr

 Main   Changelog   Spec   Patches   Sources   Download   Gear   Bugs and FR  Repocop 

Patch: vdr-1.3.14-subtitles-0.3.4-and-ttxtsubs-0.0.5.diff
Download


diff -Nru vdr-1.3.14-vanilla/Makefile vdr-1.3.14-subtitles/Makefile
--- vdr-1.3.14-vanilla/Makefile	2004-10-16 14:58:14.000000000 +0300
+++ vdr-1.3.14-subtitles/Makefile	2004-10-24 18:38:51.218767352 +0300
@@ -40,6 +40,8 @@
        skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\
        timers.o tools.o transfer.o vdr.o videodir.o
 
+OBJS += osdcontroller.o rcontroller.o dvbsub.o vdrttxtsubshooks.o
+
 FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
 OSDFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
 SMLFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-1
diff -Nru vdr-1.3.14-vanilla/dvbplayer.c vdr-1.3.14-subtitles/dvbplayer.c
--- vdr-1.3.14-vanilla/dvbplayer.c	2004-10-23 15:39:35.000000000 +0300
+++ vdr-1.3.14-subtitles/dvbplayer.c	2004-10-24 18:38:51.221766896 +0300
@@ -14,6 +14,9 @@
 #include "ringbuffer.h"
 #include "thread.h"
 #include "tools.h"
+#include "rcontroller.h"
+#include "dvbsub.h"
+#include "vdrttxtsubshooks.h"
 
 // --- cBackTrace ----------------------------------------------------------
 
@@ -321,6 +324,12 @@
             int l = b[i + 4] * 256 + b[i + 5] + 6;
             switch (c) {
               case 0xBD: // dolby
+                   if (RecordingPatch::RecordingController.isExtendedPacket( b + i , l ) ) {
+                     break;
+                   }
+                   if (b[i + 8] == 0x24 && b[i + 45] >= 0x10 && b[i + 45] < 0x20) {
+                     break; // run these through the ring buffer to get somewhat correct timing for the subtitles
+                   }
                    if (Except)
                       PlayAudio(&b[i], l);
                    // continue with deleting the data - otherwise it disturbs DVB replay
@@ -347,6 +356,35 @@
      }
 }
 
+static void StripExtendedPackets(uchar *b, int Length)
+{
+  for (int i = 0; i < Length - 6; i++) {
+      if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
+         uchar c = b[i + 3];
+         int l = b[i + 4] * 256 + b[i + 5] + 6;
+         switch (c) {
+           case 0xBD: // dolby
+                {
+                if (RecordingPatch::RecordingController.isExtendedPacket(b + i , l))
+                   RecordingPatch::RecordingController.Receive( b + i, l );
+                // EBU Teletext data, ETSI EN 300 472
+                if (b[i + 8] == 0x24 && b[i + 45] >= 0x10 && b[i + 45] < 0x20)
+                   cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData(&b[i], l);
+                // continue with deleting the data - otherwise it disturbs DVB replay
+                int n = l;
+                for (int j = i; j < Length && n--; j++)
+                    b[j] = 0x00;
+                }
+                break;
+           default:
+                break;
+           }
+         if (l)
+            i += l - 1; // the loop increments, too!
+         }
+      }
+}
+
 bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
 {
   if (FileNumber > 0)
@@ -522,6 +560,8 @@
                        StripAudioPackets(p, pc, AudioTrack);
                     }
                  }
+              if (p)
+                 StripExtendedPackets(p, pc);
               if (p) {
                  int w = PlayVideo(p, pc);
                  if (w > 0) {
diff -Nru vdr-1.3.14-vanilla/dvbsub.c vdr-1.3.14-subtitles/dvbsub.c
--- vdr-1.3.14-vanilla/dvbsub.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/dvbsub.c	2004-10-24 18:38:51.260760968 +0300
@@ -0,0 +1,18 @@
+#include "dvbsub.h"
+
+cDvbSubtitlesRecording DvbSubtitlesRecording;
+
+cDvbSubtitlesRecording::cDvbSubtitlesRecording(){ 
+  query=0; 
+}
+void cDvbSubtitlesRecording::Subscribe(iPidQuery* listener){ 
+  query = listener ;
+}
+
+int cDvbSubtitlesRecording::GetPidByChannel( int DevNr, const cChannel* Channel, int Language )
+{ 
+  if (query) 
+    return query->GetPidByChannel( DevNr, Channel,Language );
+  else
+    return 0;
+}
diff -Nru vdr-1.3.14-vanilla/dvbsub.h vdr-1.3.14-subtitles/dvbsub.h
--- vdr-1.3.14-vanilla/dvbsub.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/dvbsub.h	2004-10-24 18:38:51.262760664 +0300
@@ -0,0 +1,21 @@
+class cChannel;
+class cRecordControl;
+
+class iPidQuery
+{
+public:
+  virtual int GetPidByChannel( int DevNr, const cChannel* Channel, int Language ) = 0;
+};
+class cDvbSubtitlesRecording
+{
+public:
+  cDvbSubtitlesRecording();
+  void Subscribe(iPidQuery* listener);
+private:
+  friend class cRecordControl;
+  int GetPidByChannel( int DevNr, const cChannel* Channel, int Language );
+  iPidQuery* query;
+};
+
+extern cDvbSubtitlesRecording DvbSubtitlesRecording;
+
diff -Nru vdr-1.3.14-vanilla/menu.c vdr-1.3.14-subtitles/menu.c
--- vdr-1.3.14-vanilla/menu.c	2004-10-17 13:28:27.000000000 +0300
+++ vdr-1.3.14-subtitles/menu.c	2004-10-24 18:38:51.268759752 +0300
@@ -28,6 +28,8 @@
 #include "themes.h"
 #include "timers.h"
 #include "transfer.h"
+#include "vdrttxtsubshooks.h"
+#include "dvbsub.h"
 #include "videodir.h"
 
 #define MENUTIMEOUT     120 // seconds
@@ -2771,8 +2773,13 @@
   isyslog("record %s", fileName);
   if (MakeDirs(fileName, true)) {
      const cChannel *ch = timer->Channel();
-     recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2());
+     int SubPid1 = DvbSubtitlesRecording.GetPidByChannel( device->DeviceNumber(), ch, 1 );
+     int SubPid2 = DvbSubtitlesRecording.GetPidByChannel( device->DeviceNumber(), ch, 2 );
+     cTtxtSubsRecorderBase *subsRecorder = cVDRTtxtsubsHookListener::Hook()->NewTtxtSubsRecorder(device, ch);
+     recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2(), subsRecorder, SubPid1, SubPid2);
      if (device->AttachReceiver(recorder)) {
+       if (subsRecorder)
+          subsRecorder->DeviceAttach();
         Recording.WriteSummary();
         cStatus::MsgRecording(device, Recording.Name());
         if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
diff -Nru vdr-1.3.14-vanilla/osd.c vdr-1.3.14-subtitles/osd.c
--- vdr-1.3.14-vanilla/osd.c	2004-10-16 13:31:34.000000000 +0300
+++ vdr-1.3.14-subtitles/osd.c	2004-10-24 18:38:51.271759296 +0300
@@ -15,6 +15,8 @@
 #include <sys/stat.h>
 #include <sys/unistd.h>
 #include "tools.h"
+#include "osdcontroller.h"
+#include "vdrttxtsubshooks.h"
 
 // --- cPalette --------------------------------------------------------------
 
@@ -574,6 +576,7 @@
 // --- cOsd ------------------------------------------------------------------
 
 bool cOsd::isOpen = false;
+bool cOsd::niosd  = false;
 
 cOsd::cOsd(int Left, int Top)
 {
@@ -593,6 +596,9 @@
       delete bitmaps[i];
   delete savedRegion;
   isOpen = false;
+  if (!niosd)
+     NonInteractiveOsdPatch::OsdController.Show();
+  cVDRTtxtsubsHookListener::Hook()->ShowOSD();
 }
 
 cBitmap *cOsd::GetBitmap(int Area)
@@ -714,8 +720,13 @@
   osdProvider = NULL;
 }
 
-cOsd *cOsdProvider::NewOsd(int Left, int Top)
+cOsd *cOsdProvider::NewOsd(int Left, int Top, bool dontHide)
 {
+  if (!dontHide)
+     NonInteractiveOsdPatch::OsdController.Hide();
+  cOsd::niosd = dontHide;
+  // OSD_HOOK_2 - Information to Checkpatch.sh
+  cVDRTtxtsubsHookListener::Hook()->HideOSD();
   if (cOsd::IsOpen())
      esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
   else if (osdProvider)
diff -Nru vdr-1.3.14-vanilla/osd.h vdr-1.3.14-subtitles/osd.h
--- vdr-1.3.14-vanilla/osd.h	2004-10-16 13:33:44.000000000 +0300
+++ vdr-1.3.14-subtitles/osd.h	2004-10-24 18:38:51.273758992 +0300
@@ -215,6 +215,8 @@
   cBitmap *bitmaps[MAXOSDAREAS];
   int numBitmaps;
   int left, top, width, height;
+public:
+  static bool niosd;
 protected:
   cOsd(int Left, int Top);
        ///< Initializes the OSD with the given coordinates.
@@ -327,7 +329,7 @@
   cOsdProvider(void);
       //XXX maybe parameter to make this one "sticky"??? (frame-buffer etc.)
   virtual ~cOsdProvider();
-  static cOsd *NewOsd(int Left, int Top);
+  static cOsd *NewOsd(int Left, int Top, bool dontHide = false);
       ///< Returns a pointer to a newly created cOsd object, which will be located
       ///< at the given coordinates. When the cOsd object is no longer needed, the
       ///< caller must delete it. If the OSD is already in use, or there is no OSD
diff -Nru vdr-1.3.14-vanilla/osdcontroller.c vdr-1.3.14-subtitles/osdcontroller.c
--- vdr-1.3.14-vanilla/osdcontroller.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/osdcontroller.c	2004-10-24 18:38:51.274758840 +0300
@@ -0,0 +1,132 @@
+#include "osdcontroller.h"
+#include "thread.h"
+
+namespace NonInteractiveOsdPatch
+{
+
+  class cListenerListObject : public cListObject
+  {
+  public:
+    cListenerListObject(int priority, cOsdListener* listener);
+    bool operator< (const cListObject &ListObject);
+
+    int iPriority;
+    cOsdListener* iListener;
+  };
+
+  cListenerListObject::cListenerListObject(int priority, cOsdListener* listener)
+    : cListObject(),iPriority(priority), iListener( listener )
+  {
+  }
+  bool cListenerListObject::operator< (const cListObject &ListObject)
+  {
+    
+    return iPriority > ((cListenerListObject *)&ListObject)->iPriority;
+  }
+
+  cOsdController OsdController;
+  
+  cOsdController::cOsdController()
+    : iShowing( false )
+  {
+    iMutex = new cMutex();
+    iListeners = new cList<cListenerListObject>;
+  }
+
+  cOsdController::~cOsdController()
+  {
+    delete iListeners;
+    delete iMutex;
+  }
+
+  bool cOsdController::Subscribe(  int priority, cOsdListener* listener )
+  {
+   
+    cMutexLock( iMutex );
+    if ( !listener )
+      return false;
+    
+    for ( cListenerListObject* llo = iListeners->First();
+	  llo; llo = iListeners->Next(llo))
+    {
+      // check for duplicates
+      if ( llo->iListener == listener )
+	return false;
+    }
+
+    cListenerListObject *lo = new cListenerListObject(priority, listener);
+    iListeners->Add( lo );
+    iListeners->Sort();
+
+    // Give osd to the new listener if it has higher priority
+    // than the current one
+    if ( iShowing && !iCurrent )
+    {
+      listener->Show();
+      iCurrent = lo;
+    }
+    else if ( iShowing && iCurrent && iCurrent->iPriority < priority )
+    {
+      iCurrent->iListener->Hide();
+      ShowHighest();
+
+    }
+    
+    return true;
+  }
+
+  void cOsdController::Unsubscribe( cOsdListener* listener )
+  {
+    cMutexLock( iMutex );
+    if ( !listener )
+      return;
+
+    for ( cListenerListObject* llo = iListeners->First();
+	  llo; llo = iListeners->Next(llo))
+    {
+
+      if ( llo->iListener == listener )
+      {
+	iListeners->Del( llo, true );
+	if ( iShowing && llo == iCurrent )
+	{
+	  listener->Hide();
+	  ShowHighest();
+	}
+	break;
+      }
+    }
+
+  } 
+
+  void cOsdController::Show()
+  {
+    cMutexLock( iMutex );
+    iShowing = true;
+    ShowHighest();
+
+  }
+  
+  void cOsdController::Hide()
+  {
+    cMutexLock( iMutex );
+    iShowing = false;
+    if ( iCurrent )
+      iCurrent->iListener->Hide();
+    iCurrent = NULL;
+  }
+
+  void cOsdController::ShowHighest()
+  {
+
+    cListenerListObject* llo = iListeners->First();
+
+    if ( llo )
+      llo->iListener->Show();
+
+    iCurrent = llo;
+
+  }
+
+
+}
diff -Nru vdr-1.3.14-vanilla/osdcontroller.h vdr-1.3.14-subtitles/osdcontroller.h
--- vdr-1.3.14-vanilla/osdcontroller.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/osdcontroller.h	2004-10-24 18:38:51.275758688 +0300
@@ -0,0 +1,50 @@
+#ifndef __OSDCONTROLLER_H
+#define __OSDCONTROLLER_H
+
+#include "tools.h"
+
+
+#define MAX_OSD_LISTENERS 10
+
+class cOsd;
+class cMutex;
+
+namespace NonInteractiveOsdPatch
+{
+
+  class cOsdListener
+  {
+    
+  public:
+    virtual void Show() = 0;
+    virtual void Hide() = 0;
+
+  };
+    
+  class cListenerListObject;
+
+  class cOsdController
+  {
+  public:
+    cOsdController();
+    ~cOsdController();
+    bool Subscribe( int priority, cOsdListener* listener );
+    void Unsubscribe( cOsdListener* listner );
+
+  private:
+    friend class cOsdProvider;
+    friend class cOsd;
+    void Show();
+    void Hide();
+    void ShowHighest();
+
+    bool iShowing;
+    cMutex* iMutex;
+    cListenerListObject* iCurrent;
+    cList<cListenerListObject>* iListeners;
+
+  };
+  extern cOsdController OsdController;
+
+}
+#endif
diff -Nru vdr-1.3.14-vanilla/rcontroller.c vdr-1.3.14-subtitles/rcontroller.c
--- vdr-1.3.14-vanilla/rcontroller.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/rcontroller.c	2004-10-24 18:38:51.277758384 +0300
@@ -0,0 +1,82 @@
+#include <stdlib.h>
+#include "rcontroller.h"
+#include <stdio.h>
+#define PRIVATE_STREAM_1 0xBD
+#define PES_EXTENSION_MASK 0x01
+#define PES_EXTENSION2_MASK 0x81
+namespace RecordingPatch {
+
+  cRecordingController RecordingController;
+
+  // Returns the Data Identifier or 0 if not enough data
+  unsigned char GetDataIdentifier( unsigned char* Data, int Length )
+  {
+    if ( Length < 9 )
+      return 0;
+    int hlength = Data[8];
+    if ( Length < 9 + hlength )
+      return 0;
+    return Data[ 9 + hlength - 1 ];
+  }
+
+  cRecordingController::cRecordingController()
+  {
+    listeners = (iRecordingPlugin**)malloc( sizeof(iRecordingPlugin*)*256 );
+    for (int i=0; i < 256; i++)
+      listeners[i] = 0;
+  }
+  
+  cRecordingController::~cRecordingController()
+  {
+    free (listeners);
+  }
+  void cRecordingController::Subscribe(unsigned char DataIdentifier, iRecordingPlugin* plugin)
+  {
+    if ( listeners[ DataIdentifier ] == 0 )
+      listeners[ DataIdentifier ] = plugin;
+  }
+  void cRecordingController::Unsubscribe(unsigned char DataIdentifier, iRecordingPlugin* plugin)
+  {
+    
+    if ( listeners[ DataIdentifier ] != 0 && listeners[ DataIdentifier ] == plugin )
+      listeners[ DataIdentifier ] = 0;
+    
+  }
+
+  bool cRecordingController::isExtendedPacket(unsigned char* Data, int Length)
+  {
+    if ( Length < 9 )
+      return false;
+    if ( Data[0] != 0x00 || Data[1] != 0x00 || Data[2] != 0x01 )
+      return false;
+    if ( Data[3] != PRIVATE_STREAM_1 )
+      return false;
+    
+    if ( !(Data[7] & PES_EXTENSION_MASK) )
+      return false;
+
+    int hlength = Data[8];
+    
+    if ( ( Data[ 9 + hlength - 3 ] & PES_EXTENSION2_MASK ) == 1 
+	 && Data[ 9 + hlength - 2 ] == 0x81)
+      return true;
+
+    return false;
+
+  }
+
+
+  void cRecordingController::Receive(unsigned char* Data, int Length)
+  {
+    if ( isExtendedPacket( Data, Length ) )
+    {
+      unsigned char DataIdentifier = GetDataIdentifier( Data, Length );
+      if ( listeners[ DataIdentifier ] != 0 )
+	listeners[ DataIdentifier ] -> Receive( DataIdentifier, Data, Length );
+    }
+    else
+    {
+    }
+  }
+
+} // namespace
diff -Nru vdr-1.3.14-vanilla/rcontroller.h vdr-1.3.14-subtitles/rcontroller.h
--- vdr-1.3.14-vanilla/rcontroller.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/rcontroller.h	2004-10-24 18:38:51.278758232 +0300
@@ -0,0 +1,28 @@
+#ifndef __RECORDING_PATCH_OSD_CONTROLLER_H
+#define __RECORDING_PATCH_OSD_CONTROLLER_H
+
+class cDvbPlayer;
+namespace RecordingPatch {
+
+  class iRecordingPlugin
+  {
+  public:
+    virtual void Receive(unsigned char DataIdentifier, unsigned char* Data, int Length) = 0;
+  };
+  
+  class cRecordingController
+  {
+  public:
+    cRecordingController();
+    ~cRecordingController();
+    void Subscribe(unsigned char DataIdentifier, iRecordingPlugin* plugin);
+    void Unsubscribe(unsigned char DataIdentifer, iRecordingPlugin* plugin);
+    bool isExtendedPacket(unsigned char* Data, int Length);
+    void Receive(unsigned char* Data, int Length);
+  private:
+    iRecordingPlugin** listeners;
+  };
+  extern cRecordingController RecordingController;
+
+}
+#endif
diff -Nru vdr-1.3.14-vanilla/recorder.c vdr-1.3.14-subtitles/recorder.c
--- vdr-1.3.14-vanilla/recorder.c	2004-10-16 12:23:01.000000000 +0300
+++ vdr-1.3.14-subtitles/recorder.c	2004-10-24 18:38:51.280757928 +0300
@@ -10,6 +10,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <stdint.h>
 #include "recorder.h"
 
 #define RECORDERBUFSIZE  MEGABYTE(5)
@@ -23,6 +24,7 @@
 
 class cFileWriter : public cThread {
 private:
+  cTtxtSubsRecorderBase *ttxtSubsRecorder;
   cRemux *remux;
   cFileName *fileName;
   cIndexFile *index;
@@ -36,13 +38,14 @@
 protected:
   virtual void Action(void);
 public:
-  cFileWriter(const char *FileName, cRemux *Remux);
+  cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr);
   virtual ~cFileWriter();
   };
 
-cFileWriter::cFileWriter(const char *FileName, cRemux *Remux)
+cFileWriter::cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr)
 :cThread("file writer")
 {
+  ttxtSubsRecorder = tsr;
   active = false;
   fileName = NULL;
   remux = Remux;
@@ -67,6 +70,8 @@
   Cancel(3);
   delete index;
   delete fileName;
+  if (ttxtSubsRecorder)
+     delete ttxtSubsRecorder;
 }
 
 bool cFileWriter::RunningLowOnDiskSpace(void)
@@ -113,6 +118,16 @@
                  }
               fileSize += Count;
               remux->Del(Count);
+              // not sure if the pictureType test is needed, but it seems we can get
+              // incomplete pes packets from remux if we are not getting pictures?
+              if (ttxtSubsRecorder && pictureType != NO_PICTURE) {
+                 uint8_t *subsp;
+                 size_t len;
+                 if (ttxtSubsRecorder->GetPacket(&subsp, &len)) {
+                    safe_write(recordFile, subsp, len);
+                    fileSize += len;
+                    }
+                 }
               }
            else
               break;
@@ -127,8 +142,8 @@
   active = false;
 }
 
-cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2)
-:cReceiver(Ca, Priority, Setup.RecordDolbyDigital ? 5 : 3, VPid, APid1, APid2, DPid1, DPid2)
+cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2, cTtxtSubsRecorderBase *tsr, int SubPid1, int SubPid2)
+:cReceiver(Ca, Priority, Setup.RecordDolbyDigital ? 7 : 5, VPid, APid1, APid2, SubPid1, SubPid2, DPid1, DPid2)
 ,cThread("recording")
 {
   active = false;
@@ -139,8 +154,8 @@
 
   ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder");
   ringBuffer->SetTimeouts(0, 100);
-  remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
-  writer = new cFileWriter(FileName, remux);
+  remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true, SubPid1, SubPid2);
+  writer = new cFileWriter(FileName, remux, tsr);
 }
 
 cRecorder::~cRecorder()
diff -Nru vdr-1.3.14-vanilla/recorder.h vdr-1.3.14-subtitles/recorder.h
--- vdr-1.3.14-vanilla/recorder.h	2004-10-10 14:22:38.000000000 +0300
+++ vdr-1.3.14-subtitles/recorder.h	2004-10-24 18:38:51.281757776 +0300
@@ -15,6 +15,7 @@
 #include "remux.h"
 #include "ringbuffer.h"
 #include "thread.h"
+#include "vdrttxtsubshooks.h"
 
 class cFileWriter;
 
@@ -29,7 +30,7 @@
   virtual void Receive(uchar *Data, int Length);
   virtual void Action(void);
 public:
-  cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2);
+  cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2, cTtxtSubsRecorderBase *tsr, int SubPid1 = 0, int SubPid2 = 0);
                // Creates a new recorder that requires conditional access Ca, has
                // the given Priority and will record the given PIDs into the file FileName.
   virtual ~cRecorder();
diff -Nru vdr-1.3.14-vanilla/remux.c vdr-1.3.14-subtitles/remux.c
--- vdr-1.3.14-vanilla/remux.c	2004-10-24 12:25:33.000000000 +0300
+++ vdr-1.3.14-subtitles/remux.c	2004-10-24 18:38:51.284757320 +0300
@@ -42,6 +42,9 @@
 //pts_dts flags
 #define PTS_ONLY         0x80
 
+#define PES_EXTENSION    0x01
+#define PES_EXTENSION2   0x01
+
 #define TS_SIZE        188
 #define PID_MASK_HI    0x1F
 #define CONT_CNT_MASK  0x0F
@@ -83,6 +86,8 @@
   int tsErrors;
   int ccErrors;
   int ccCounter;
+  uint8_t dataIdentifier;
+  static uint8_t eHeadr[];
   static uint8_t headr[];
   void store(uint8_t *Data, int Count);
   void reset_ipack(void);
@@ -90,15 +95,16 @@
   void write_ipack(const uint8_t *Data, int Count);
   void instant_repack(const uint8_t *Buf, int Count);
 public:
-  cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid = 0x00);
+  cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid = 0x00, uint8_t DataIndentifier = 0x00);
   ~cTS2PES();
   void ts_to_pes(const uint8_t *Buf); // don't need count (=188)
   void Clear(void);
   };
 
+uint8_t cTS2PES::eHeadr[] = { 0x01, 0x81 }; // extension header
 uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 };
 
-cTS2PES::cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid)
+cTS2PES::cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid, uint8_t DataIdentifier)
 {
   resultBuffer = ResultBuffer;
   size = Size;
@@ -107,6 +113,7 @@
   tsErrors = 0;
   ccErrors = 0;
   ccCounter = -1;
+  dataIdentifier = DataIdentifier;
 
   if (!(buf = MALLOC(uint8_t, size)))
      esyslog("Not enough memory for ts_transform");
@@ -159,10 +166,21 @@
 
   switch (mpeg) {
     case 2:
+         if ( dataIdentifier == 0 ) {
             buf[6] = 0x80;
             buf[7] = 0x00;
             buf[8] = 0x00;
             count = 9;
+            }
+         else {
+            buf[6] = 0x80;
+            buf[7] = 0x01; // pes_extension_flag == 1
+            buf[8] = 0x03; // pes_header_data_length == 3
+            buf[9] = 0x01; // pes_extension_flag_2=1
+            buf[10]= 0x81; // marker_bit=1, pes_extension_data_length=1 
+            buf[11] = dataIdentifier;
+            count = 12;
+            }
             break;
     case 1:
             buf[6] = 0x0F;
@@ -273,12 +291,21 @@
           case 7:
                   if (!done && mpeg == 2) {
                      flag2 = Buf[c++];
+                     if ( dataIdentifier && (flag2 & PES_EXTENSION) ) {
+                        esyslog("Error: cannot add extension to pes packet. Disabling.");
+                        dataIdentifier = 0;
+                        }
+                     else {
+                        flag2 |= PES_EXTENSION;
+                        }
                      found++;
                      }
                   break;
           case 8:
                   if (!done && mpeg == 2) {
                      hlength = Buf[c++];
+                     if ( dataIdentifier )
+                        hlength += 3;
                      found++;
                      }
                   break;
@@ -315,6 +342,20 @@
                   return;
                }
 
+            // Write header one byte at a time
+            // Remove from hlength size of our header (3)
+            if ( dataIdentifier ) {
+               while (c < Count && (found < (hlength + 9-3)) && found < plength+6) {
+                     write_ipack(Buf + c, 1);
+                     c++;
+                     found++;
+                     }
+               if (found == (hlength+9-3)) {
+                  write_ipack(eHeadr, 2); 
+                  write_ipack(&dataIdentifier, 1);
+                  }
+               }
+
             while (c < Count && found < plength + 6) {
                   int l = Count - c;
                   if (l + found > plength + 6)
@@ -395,13 +436,15 @@
 
 #define RESULTBUFFERSIZE KILOBYTE(256)
 
-cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure)
+cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure, int SubPid1, int SubPid2)
 {
   vPid = VPid;
   aPid1 = APid1;
   aPid2 = APid2;
   dPid1 = DPid1;
   dPid2 = DPid2;
+  sPid1 = SubPid1;
+  sPid2 = SubPid2;
   exitOnFailure = ExitOnFailure;
   numUPTerrors = 0;
   synced = false;
@@ -415,6 +458,8 @@
   dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, IPACKS)       : NULL;
   //XXX don't yet know how to tell apart primary and secondary DD data...
   dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, IPACKS) : XXX*/ NULL;
+  sTS2PES1 = SubPid1 ? new cTS2PES(resultBuffer, IPACKS, 0x00, 0x28) : NULL;
+  sTS2PES2 = SubPid2 ? new cTS2PES(resultBuffer, IPACKS, 0x00, 0x29) : NULL;
 }
 
 cRemux::~cRemux()
@@ -424,6 +469,8 @@
   delete aTS2PES2;
   delete dTS2PES1;
   delete dTS2PES2;
+  delete sTS2PES1;
+  delete sTS2PES2;
   delete resultBuffer;
 }
 
@@ -500,6 +547,8 @@
          else if (pid == aPid2 && aTS2PES2) aTS2PES2->ts_to_pes(Data + i);
          else if (pid == dPid1 && dTS2PES1) dTS2PES1->ts_to_pes(Data + i);
          else if (pid == dPid2 && dTS2PES2) dTS2PES2->ts_to_pes(Data + i);
+         else if (pid == sPid1 && sTS2PES1) sTS2PES1->ts_to_pes(Data + i);
+         else if (pid == sPid2 && sTS2PES2) sTS2PES2->ts_to_pes(Data + i);
          }
       used += TS_SIZE;
       }
diff -Nru vdr-1.3.14-vanilla/remux.h vdr-1.3.14-subtitles/remux.h
--- vdr-1.3.14-vanilla/remux.h	2004-10-15 15:31:16.000000000 +0300
+++ vdr-1.3.14-subtitles/remux.h	2004-10-24 18:38:51.285757168 +0300
@@ -29,15 +29,15 @@
   int numUPTerrors;
   bool synced;
   int skipped;
-  int vPid, aPid1, aPid2, dPid1, dPid2;
-  cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2, *dTS2PES1, *dTS2PES2;
+  int vPid, aPid1, aPid2, dPid1, dPid2, sPid1, sPid2;
+  cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2, *dTS2PES1, *dTS2PES2, *sTS2PES1, *sTS2PES2;
   cRingBufferLinear *resultBuffer;
   int resultSkipped;
   int GetPid(const uchar *Data);
   int GetPacketLength(const uchar *Data, int Count, int Offset);
   int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
 public:
-  cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure = false);
+  cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure = false, int SubPid1 = 0, int SubPid2 = 0);
   ~cRemux();
   int Put(const uchar *Data, int Count);
        ///< Puts at most Count bytes of Data into the remuxer.
diff -Nru vdr-1.3.14-vanilla/vdrttxtsubshooks.c vdr-1.3.14-subtitles/vdrttxtsubshooks.c
--- vdr-1.3.14-vanilla/vdrttxtsubshooks.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/vdrttxtsubshooks.c	2004-10-24 18:38:51.286757016 +0300
@@ -0,0 +1,44 @@
+
+#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)
+    { if(gListener) gListener->PlayerTeletextData(p, length); };
+  virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch)
+    { if(gListener) return gListener->NewTtxtSubsRecorder(dev, ch); else return NULL; };
+};
+
+
+// ------ 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 -Nru vdr-1.3.14-vanilla/vdrttxtsubshooks.h vdr-1.3.14-subtitles/vdrttxtsubshooks.h
--- vdr-1.3.14-vanilla/vdrttxtsubshooks.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.3.14-subtitles/vdrttxtsubshooks.h	2004-10-24 18:38:51.287756864 +0300
@@ -0,0 +1,36 @@
+
+#ifndef __VDRTTXTSUBSHOOKS_H
+#define __VDRTTXTSUBSHOOKS_H
+
+class cDevice;
+class cChannel;
+
+#define VDRTTXTSUBSHOOKS
+
+class cTtxtSubsRecorderBase {
+ public:
+  virtual ~cTtxtSubsRecorderBase() {};
+
+  // returns a PES packet if there is data to add to the recording
+  virtual uint8_t *GetPacket(uint8_t **buf, size_t *len) { return NULL; };
+  virtual void DeviceAttach(void) {};
+};
+
+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) {};
+  virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch)
+    { return NULL; };
+
+  // used by VDR to call hook listeners
+  static cVDRTtxtsubsHookListener *Hook(void);
+};
+
+#endif
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin