Sophie

Sophie

distrib > Mandriva > 2007.1 > x86_64 > by-pkgid > fdddaca718fdaac56c6bff726f3554dd > files > 20

vdr-1.4.7-9mdv2007.1.src.rpm

diff -Nru vdr-1.4.7-vanilla/Makefile vdr-1.4.7-subtitles/Makefile
--- vdr-1.4.7-vanilla/Makefile	2006-08-20 13:44:22.000000000 +0300
+++ vdr-1.4.7-subtitles/Makefile	2007-10-11 21:27:00.000000000 +0300
@@ -39,6 +39,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.4.7-vanilla/dvbplayer.c vdr-1.4.7-subtitles/dvbplayer.c
--- vdr-1.4.7-vanilla/dvbplayer.c	2007-04-28 17:55:22.000000000 +0300
+++ vdr-1.4.7-subtitles/dvbplayer.c	2007-10-11 21:27:00.000000000 +0300
@@ -14,6 +14,9 @@
 #include "ringbuffer.h"
 #include "thread.h"
 #include "tools.h"
+#include "rcontroller.h"
+#include "dvbsub.h"
+#include "vdrttxtsubshooks.h"
 
 // --- cBackTrace ------------------------------------------------------------
 
@@ -312,6 +315,39 @@
   firstPacket = true;
 }
 
+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 );
+                   // continue with deleting the data - otherwise it disturbs DVB replay
+                   int n = l;
+                   for (int j = i; j < Length && n--; j++)
+                       b[j] = 0x00;
+                   }
+                // EBU Teletext data, ETSI EN 300 472
+                else 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)
@@ -497,6 +533,7 @@
                     }
                  }
               if (p) {
+                 StripExtendedPackets(p, pc);
                  int w = PlayPes(p, pc, playMode != pmPlay);
                  if (w > 0) {
                     p += w;
diff -Nru vdr-1.4.7-vanilla/dvbsub.c vdr-1.4.7-subtitles/dvbsub.c
--- vdr-1.4.7-vanilla/dvbsub.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/dvbsub.c	2007-10-11 21:27:00.000000000 +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.4.7-vanilla/dvbsub.h vdr-1.4.7-subtitles/dvbsub.h
--- vdr-1.4.7-vanilla/dvbsub.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/dvbsub.h	2007-10-11 21:27:00.000000000 +0300
@@ -0,0 +1,22 @@
+class cChannel;
+class cRecordControl;
+
+class iPidQuery
+{
+public:
+  virtual ~iPidQuery() {};
+  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.4.7-vanilla/menu.c vdr-1.4.7-subtitles/menu.c
--- vdr-1.4.7-vanilla/menu.c	2006-12-02 13:12:02.000000000 +0200
+++ vdr-1.4.7-subtitles/menu.c	2007-10-11 21:27:00.000000000 +0300
@@ -27,6 +27,8 @@
 #include "themes.h"
 #include "timers.h"
 #include "transfer.h"
+#include "vdrttxtsubshooks.h"
+#include "dvbsub.h"
 #include "videodir.h"
 
 #define MAXWAIT4EPGINFO   3 // seconds
@@ -3541,8 +3543,11 @@
   isyslog("record %s", fileName);
   if (MakeDirs(fileName, true)) {
      const cChannel *ch = timer->Channel();
-     recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
+     cTtxtSubsRecorderBase *subsRecorder = cVDRTtxtsubsHookListener::Hook()->NewTtxtSubsRecorder(device, ch);
+     int SubPids[3] = {DvbSubtitlesRecording.GetPidByChannel(device->DeviceNumber(), ch, 1), DvbSubtitlesRecording.GetPidByChannel(device->DeviceNumber(), ch, 2), 0};
+     recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), SubPids, subsRecorder);
      if (device->AttachReceiver(recorder)) {
+        if (subsRecorder) subsRecorder->DeviceAttach();
         Recording.WriteInfo();
         cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
         if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
diff -Nru vdr-1.4.7-vanilla/osd.c vdr-1.4.7-subtitles/osd.c
--- vdr-1.4.7-vanilla/osd.c	2007-02-17 18:05:52.000000000 +0200
+++ vdr-1.4.7-subtitles/osd.c	2007-10-11 21:27:00.000000000 +0300
@@ -14,6 +14,8 @@
 #include <sys/stat.h>
 #include <sys/unistd.h>
 #include "tools.h"
+#include "osdcontroller.h"
+#include "vdrttxtsubshooks.h"
 
 // --- cPalette --------------------------------------------------------------
 
@@ -602,6 +604,7 @@
 // --- cOsd ------------------------------------------------------------------
 
 int cOsd::isOpen = 0;
+bool cOsd::niosd  = false;
 
 cOsd::cOsd(int Left, int Top)
 {
@@ -621,6 +624,9 @@
       delete bitmaps[i];
   delete savedRegion;
   isOpen--;
+  if (!niosd)
+     NonInteractiveOsdPatch::OsdController.Show();
+  cVDRTtxtsubsHookListener::Hook()->ShowOSD();
 }
 
 cBitmap *cOsd::GetBitmap(int Area)
@@ -744,8 +750,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.4.7-vanilla/osd.h vdr-1.4.7-subtitles/osd.h
--- vdr-1.4.7-vanilla/osd.h	2006-02-26 16:45:05.000000000 +0200
+++ vdr-1.4.7-subtitles/osd.h	2007-10-11 21:27:00.000000000 +0300
@@ -222,6 +222,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.
@@ -337,7 +339,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.4.7-vanilla/osdcontroller.c vdr-1.4.7-subtitles/osdcontroller.c
--- vdr-1.4.7-vanilla/osdcontroller.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/osdcontroller.c	2007-10-11 21:27:00.000000000 +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.4.7-vanilla/osdcontroller.h vdr-1.4.7-subtitles/osdcontroller.h
--- vdr-1.4.7-vanilla/osdcontroller.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/osdcontroller.h	2007-10-11 21:27:00.000000000 +0300
@@ -0,0 +1,52 @@
+#ifndef __OSDCONTROLLER_H
+#define __OSDCONTROLLER_H
+
+#include "tools.h"
+
+
+#define MAX_OSD_LISTENERS 10
+
+class cOsdProvider;
+class cOsd;
+class cMutex;
+
+namespace NonInteractiveOsdPatch
+{
+
+  class cOsdListener
+  {
+    
+  public:
+    virtual ~cOsdListener() {};
+    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.4.7-vanilla/rcontroller.c vdr-1.4.7-subtitles/rcontroller.c
--- vdr-1.4.7-vanilla/rcontroller.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/rcontroller.c	2007-10-11 21:27:00.000000000 +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.4.7-vanilla/rcontroller.h vdr-1.4.7-subtitles/rcontroller.h
--- vdr-1.4.7-vanilla/rcontroller.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/rcontroller.h	2007-10-11 21:27:00.000000000 +0300
@@ -0,0 +1,29 @@
+#ifndef __RECORDING_PATCH_OSD_CONTROLLER_H
+#define __RECORDING_PATCH_OSD_CONTROLLER_H
+
+class cDvbPlayer;
+namespace RecordingPatch {
+
+  class iRecordingPlugin
+  {
+  public:
+    virtual ~iRecordingPlugin() {};
+    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.4.7-vanilla/recorder.c vdr-1.4.7-subtitles/recorder.c
--- vdr-1.4.7-vanilla/recorder.c	2006-01-08 13:01:25.000000000 +0200
+++ vdr-1.4.7-subtitles/recorder.c	2007-10-11 21:27:00.000000000 +0300
@@ -11,6 +11,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <stdint.h>
 
 #define RECORDERBUFSIZE  MEGABYTE(5)
 
@@ -23,6 +24,7 @@
 
 class cFileWriter : public cThread {
 private:
+  cTtxtSubsRecorderBase *ttxtSubsRecorder;
   cRemux *remux;
   cFileName *fileName;
   cIndexFile *index;
@@ -35,13 +37,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;
   fileName = NULL;
   remux = Remux;
   index = NULL;
@@ -64,6 +67,8 @@
   Cancel(3);
   delete index;
   delete fileName;
+  if (ttxtSubsRecorder)
+     delete ttxtSubsRecorder;
 }
 
 bool cFileWriter::RunningLowOnDiskSpace(void)
@@ -108,6 +113,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)) {
+                    recordFile->Write(subsp, len);
+                    fileSize += len;
+                    }
+                 }
               }
            else
               break;
@@ -121,7 +136,7 @@
         }
 }
 
-cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids)
+cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids, cTtxtSubsRecorderBase *tsr)
 :cReceiver(Ca, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
 ,cThread("recording")
 {
@@ -132,7 +147,7 @@
   ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder");
   ringBuffer->SetTimeouts(0, 100);
   remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, true);
-  writer = new cFileWriter(FileName, remux);
+  writer = new cFileWriter(FileName, remux, tsr);
 }
 
 cRecorder::~cRecorder()
diff -Nru vdr-1.4.7-vanilla/recorder.h vdr-1.4.7-subtitles/recorder.h
--- vdr-1.4.7-vanilla/recorder.h	2005-08-13 14:31:18.000000000 +0300
+++ vdr-1.4.7-subtitles/recorder.h	2007-10-11 21:27:00.000000000 +0300
@@ -15,6 +15,7 @@
 #include "remux.h"
 #include "ringbuffer.h"
 #include "thread.h"
+#include "vdrttxtsubshooks.h"
 
 class cFileWriter;
 
@@ -28,7 +29,7 @@
   virtual void Receive(uchar *Data, int Length);
   virtual void Action(void);
 public:
-  cRecorder(const char *FileName, int Ca, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids);
+  cRecorder(const char *FileName, int Ca, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids, cTtxtSubsRecorderBase *tsr);
                // 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.4.7-vanilla/remux.c vdr-1.4.7-subtitles/remux.c
--- vdr-1.4.7-vanilla/remux.c	2006-12-01 16:46:25.000000000 +0200
+++ vdr-1.4.7-subtitles/remux.c	2007-10-11 21:27:34.000000000 +0300
@@ -1413,6 +1413,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
@@ -1461,6 +1464,8 @@
   int ccErrors;
   int ccCounter;
   cRepacker *repacker;
+  uint8_t dataIdentifier;
+  static uint8_t eHeadr[];
   static uint8_t headr[];
   void store(uint8_t *Data, int Count);
   void reset_ipack(void);
@@ -1468,16 +1473,18 @@
   void write_ipack(const uint8_t *Data, int Count);
   void instant_repack(const uint8_t *Buf, int Count);
 public:
-  cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t RewriteCid = 0x00, uint8_t SubStreamId = 0x00, cRepacker *Repacker = NULL);
+  cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t RewriteCid = 0x00, uint8_t SubStreamId = 0x00, cRepacker *Repacker = NULL, uint8_t DataIdentifier = 0x00);
+
   ~cTS2PES();
   int Pid(void) { return pid; }
   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(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t RewriteCid, uint8_t SubStreamId, cRepacker *Repacker)
+cTS2PES::cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t RewriteCid, uint8_t SubStreamId, cRepacker *Repacker, uint8_t DataIdentifier)
 {
   pid = Pid;
   resultBuffer = ResultBuffer;
@@ -1494,6 +1501,7 @@
   tsErrors = 0;
   ccErrors = 0;
   ccCounter = -1;
+  dataIdentifier = DataIdentifier;
 
   if (!(buf = MALLOC(uint8_t, size)))
      esyslog("Not enough memory for ts_transform");
@@ -1551,10 +1559,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;
@@ -1717,12 +1736,22 @@
           case 7:
                   if (!done && (mpeg == 2 || mpeg1_required > 7)) {
                      flag2 = Buf[c++];
+                     if (dataIdentifier) {
+                        if (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 || mpeg1_required > 7)) {
                      hlength = Buf[c++];
+                     if (dataIdentifier)
+                        hlength += 3;
                      found++;
                      if (mpeg == 1 && hlength != 0x0F && (hlength & 0xF0) != 0x20 && (hlength & 0xF0) != 0x30)
                         found = 0; // invalid MPEG1 header
@@ -1766,6 +1795,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)
@@ -1888,13 +1931,11 @@
      while (*DPids && numTracks < MAXTRACKS && n < MAXDPIDS)
            ts2pes[numTracks++] = new cTS2PES(*DPids++, resultBuffer, IPACKS, 0x00, 0x80 + n++, new cDolbyRepacker);
      }
-  /* future...
   if (SPids) {
      int n = 0;
      while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS)
-           ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x28 + n++);
+           ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x00, NULL, 0x28 + n++);
      }
-  */
 }
 
 cRemux::~cRemux()
diff -Nru vdr-1.4.7-vanilla/vdr.c vdr-1.4.7-subtitles/vdr.c
--- vdr-1.4.7-vanilla/vdr.c	2007-04-30 12:48:23.000000000 +0300
+++ vdr-1.4.7-subtitles/vdr.c	2007-10-11 21:27:00.000000000 +0300
@@ -851,7 +851,7 @@
            DeletedRecordings.Update();
            }
         // CAM control:
-        if (!Menu && !cOsd::IsOpen()) {
+        if (!Menu && !(cOsd::IsOpen() && !cOsd::niosd)) {
            Menu = CamControl();
            if (Menu)
               LastCamMenu = 0;
@@ -878,7 +878,7 @@
                if (Menu)
                   DELETE_MENU;
                else if (cControl::Control()) {
-                  if (cOsd::IsOpen())
+                  if (cOsd::IsOpen() && !cOsd::niosd)
                      cControl::Control()->Hide();
                   else
                      WasOpen = false;
@@ -969,7 +969,7 @@
                   }
                else
                   cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
-               if (!Menu && !cOsd::IsOpen())
+               if (!Menu && !(cOsd::IsOpen() && !cOsd::niosd))
                   Menu = cDisplayVolume::Create();
                cDisplayVolume::Process(key);
                key = kNone; // nobody else needs to see these keys
diff -Nru vdr-1.4.7-vanilla/vdrttxtsubshooks.c vdr-1.4.7-subtitles/vdrttxtsubshooks.c
--- vdr-1.4.7-vanilla/vdrttxtsubshooks.c	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/vdrttxtsubshooks.c	2007-10-11 21:27:00.000000000 +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.4.7-vanilla/vdrttxtsubshooks.h vdr-1.4.7-subtitles/vdrttxtsubshooks.h
--- vdr-1.4.7-vanilla/vdrttxtsubshooks.h	1970-01-01 02:00:00.000000000 +0200
+++ vdr-1.4.7-subtitles/vdrttxtsubshooks.h	2007-10-11 21:27:00.000000000 +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