From 3a81d2944e05d9212a7f5dae6b15351df7f79760 Mon Sep 17 00:00:00 2001
From: Mark Calderbank <mark@vomp.tv>
Date: Sat, 6 Dec 2008 15:08:34 +0000
Subject: [PATCH] DVB Subtitles: Live TV

---
 demuxer.cc      |   8 ++++
 demuxerts.cc    | 109 +++++++++++++++++++++++++++++++++++-------------
 demuxerts.h     |   9 +++-
 demuxervdr.cc   |   5 ++-
 dvbsubtitles.cc |   4 +-
 playerlivetv.cc |  38 ++++++++++++++++-
 playerlivetv.h  |   8 +++-
 vvideolivetv.cc |  28 ++++++++++++-
 vvideolivetv.h  |   8 +++-
 9 files changed, 177 insertions(+), 40 deletions(-)

diff --git a/demuxer.cc b/demuxer.cc
index 931f33f..21a6eb6 100644
--- a/demuxer.cc
+++ b/demuxer.cc
@@ -22,6 +22,7 @@
 #include "demuxer.h"
 
 #include "callback.h"
+#include "dvbsubtitles.h"
 #include "log.h"
 
 #define DEMUXER_SEQ_HEAD 0x000001B3
@@ -301,6 +302,12 @@ bool Demuxer::submitPacket(PESPacket& packet)
       sent = packet.getSize();
     }
   }
+  else if (packet_type == PESTYPE_PRIVATE_1 &&
+           packet.getSubstream() == 0x20)
+  {
+    if (subtitles) subtitles->put(packet);
+    sent = packet.getSize();
+  }
   else
   {
     sent = packet.getSize();
@@ -355,6 +362,7 @@ pre_1_3_19_Recording: //This is for old recordings stuff and live TV
     {
       case 0x20://SPU
       case 0x30://SPU
+        packet.setSubstream(substream_id);
         break;
       case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?
         break;
diff --git a/demuxerts.cc b/demuxerts.cc
index 2b1acd2..03c6a9c 100644
--- a/demuxerts.cc
+++ b/demuxerts.cc
@@ -1,5 +1,5 @@
 /*
-    Copyright 2006-2007 Mark Calderbank
+    Copyright 2006-2008 Mark Calderbank
 
     This file is part of VOMP.
 
@@ -14,18 +14,20 @@
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
 
 #include "demuxerts.h"
 #include "log.h"
 
-DemuxerTS::DemuxerTS(int p_vID, int p_aID)
+DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID)
 {
-  vID = p_vID;
-  aID = p_aID;
+  vID = p_vID; vActive = false;
+  aID = p_aID; aActive = false;
+  subID = p_subID; subActive = false;
   atype = 0;
+  subLength = 0;
 }
 
 void DemuxerTS::flush()
@@ -34,27 +36,33 @@ void DemuxerTS::flush()
   parsed = false;
   Demuxer::flush();
   vPacket.init(PESTYPE_VID0);
-  switch (atype) {
+  switch (atype)
+  {
   case 1:
-  aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);break;
+    aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
+    break;
   default:
   case 0:
-  aPacket.init(PESTYPE_AUD0);break;
-  };
+    aPacket.init(PESTYPE_AUD0);
+    break;
+  }
+  subPacket.init(PESTYPE_PRIVATE_1);
   vActive = false;
   aActive = false;
+  subActive = false;
+  subLength = 0;
 }
 
 int DemuxerTS::scan(UCHAR *buf, int len)
 {
-  switch (atype) {
+  switch (atype)
+  {
   case 1:
-  return PESTYPE_PRIVATE_1;
+    return PESTYPE_PRIVATE_1;
   default:
   case 0:
-  return PESTYPE_AUD0;
-  };
-  
+    return PESTYPE_AUD0;
+  }
 }
 
 void DemuxerTS::setVID(int p_vID)
@@ -68,19 +76,29 @@ void DemuxerTS::setAID(int p_aID, int type)
 {
   aID = p_aID;
   atype = type;
-  switch (atype) {
+  switch (atype)
+  {
   case 1:
-  aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);
-  setAudioStream(PESTYPE_SUBSTREAM_AC30);break;
+    aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
+    setAudioStream(PESTYPE_SUBSTREAM_AC30);
+    break;
   default:
   case 0:
-  aPacket.init(PESTYPE_AUD0);
-  setAudioStream(PESTYPE_AUD0);
-  break;
-  };
+    aPacket.init(PESTYPE_AUD0);
+    setAudioStream(PESTYPE_AUD0);
+    break;
+  }
   aActive = false;
 }
 
+void DemuxerTS::setSubID(int p_subID)
+{
+  subID = p_subID;
+  subPacket.init(PESTYPE_PRIVATE_1);
+  subActive = false;
+  subLength = 0;
+}
+
 int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
 {
   UINT LoPattern = 0x100 | PESTYPE_VID0,
@@ -219,7 +237,7 @@ int DemuxerTS::processTS(UCHAR* buf)
           parsePacketDetails(vPacket);
           parsed = true;
         }
-      rc = submitPacket(vPacket);
+        rc = submitPacket(vPacket);
       }
       vActive = true;
     }
@@ -232,10 +250,24 @@ int DemuxerTS::processTS(UCHAR* buf)
           parsePacketDetails(aPacket);
           parsed = true;
         }
-      rc = submitPacket(aPacket);
+        rc = submitPacket(aPacket);
       }
       aActive = true;
     }
+    if (pid == subID)
+    {
+      if (subActive)
+      {
+        if (!parsed)
+        {
+          parsePacketDetails(subPacket);
+          parsed = true;
+        }
+        rc = submitPacket(subPacket);
+      }
+      subActive = true;
+    }
+        
     if (rc == 0) return 0;
 
     parsed = false;
@@ -246,23 +278,34 @@ int DemuxerTS::processTS(UCHAR* buf)
     }
     if (pid == aID)
     {
-      switch (atype) {
+      switch (atype)
+      {
       case 1:
-          aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);break;
+        aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
+        break;
       default:
       case 0:
-      aPacket.init(PESTYPE_AUD0);break;
-      };
+        aPacket.init(PESTYPE_AUD0);
+        break;
+      }
+      buf += 6; datalen -= 6;
+    }
+    if (pid == subID)
+    {
+      subPacket.init(PESTYPE_PRIVATE_1);
+      subLength = (buf[4] << 8) + buf[5];
       buf += 6; datalen -= 6;
     }
   }
 
   if ( (pid == vID && vActive) ||
-       (pid == aID && aActive) )
+       (pid == aID && aActive) ||
+       (pid == subID && subActive) )
   {
     PESPacket* packet = NULL;
     if (pid == vID) packet = &vPacket;
     if (pid == aID) packet = &aPacket;
+    if (pid == subID) packet = &subPacket;
     if (packet != NULL)
     {
       if (packet->write(buf, datalen) == 0)
@@ -281,5 +324,13 @@ int DemuxerTS::processTS(UCHAR* buf)
     }
   }
 
+  if (pid == subID && subActive && subPacket.getLength() == subLength)
+  {
+    parsePacketDetails(subPacket);
+Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());
+    submitPacket(subPacket);
+    subActive = false;
+  }
+
   return 1;
 }
diff --git a/demuxerts.h b/demuxerts.h
index e58ef7b..0df7cd6 100644
--- a/demuxerts.h
+++ b/demuxerts.h
@@ -30,14 +30,16 @@
 class DemuxerTS : public Demuxer
 {
   public:
-    DemuxerTS(int p_vID = 0, int p_aID = 0);
+    DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0);
     void flush();
     int scan(UCHAR* buf, int len);
     int findPTS(UCHAR* buf, int len, ULLONG* dest);
     void setVID(int p_vID);
     void setAID(int p_aID, int type);
+    void setSubID(int p_subID);
     int  getVID() { return vID; }
     int  getAID() { return aID; }
+    int  getSubID() { return subID; }
     int put(UCHAR* buf, int len);
 
   private:
@@ -48,9 +50,12 @@ class DemuxerTS : public Demuxer
     bool parsed;       // Whether PES packet to be submitted has been parsed yet
     PESPacket vPacket; // Video PES packet under construction
     PESPacket aPacket; // Audio PES packet under construction
-    int vID, aID;      // TS IDs for video/audio
+    PESPacket subPacket; // Subtitles PES packet under construction
+    int vID, aID, subID; // TS IDs for video/audio/subtitles
     int atype;
     bool vActive, aActive; // Whether video/audio is actively being captured
+    bool subActive;        // Same for subtitles
+    UINT subLength;        // Expected length of subtitle packet
 };
 
 #endif
diff --git a/demuxervdr.cc b/demuxervdr.cc
index 4ff9698..7f3bafc 100644
--- a/demuxervdr.cc
+++ b/demuxervdr.cc
@@ -323,8 +323,9 @@ void DemuxerVDR::dealWithSubtitlePacket()
   while (subtitlePacketPosition < subSize)
   {
     if (sub_data[subtitlePacketPosition] == 0xFF)
-    {
-      subtitles->put(subtitlePacket);
+    { // Packet is complete. Switch it into the "real" packet to be submitted.
+      packet = subtitlePacket;
+      parsePacketDetails(packet);
       subtitlePacketPosition = 0; // Wait for next non-continuation packet
       break;
     }
diff --git a/dvbsubtitles.cc b/dvbsubtitles.cc
index 43c3932..692d0a3 100644
--- a/dvbsubtitles.cc
+++ b/dvbsubtitles.cc
@@ -502,8 +502,8 @@ void DVBSubtitles::put(const PESPacket& packet)
   {
     if (packet.getPTS() != PESPacket::PTS_INVALID)
     {
-    worklist.push_back(packet);
-    nudge();
+      worklist.push_back(packet);
+      nudge();
     }
   }
   unlockInput();
diff --git a/playerlivetv.cc b/playerlivetv.cc
index 85230eb..5df0680 100644
--- a/playerlivetv.cc
+++ b/playerlivetv.cc
@@ -29,14 +29,17 @@
 #include "remote.h"
 #include "message.h"
 #include "channel.h"
+#include "dvbsubtitles.h"
+#include "osdreceiver.h"
 
 // ----------------------------------- Called from outside, one offs or info funcs
 
-PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
+PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
 : vfeed(this), afeed(this)
 {
   messageQueue = tmessageQueue;
   messageReceiver = tmessageReceiver;
+  osdReceiver = tosdReceiver;
   chanList = tchanList;
   
   audio = Audio::getInstance();
@@ -45,6 +48,7 @@ PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver,
   vdr = VDR::getInstance();
   initted = false;
 
+  subtitlesShowing = false;
   videoStartup = false;
 
   stopNow = false;
@@ -64,8 +68,10 @@ int PlayerLiveTV::init()
 
   demuxer = new DemuxerTS();
   if (!demuxer) return 0;
+  subtitles = new DVBSubtitles(osdReceiver);
+  if (!subtitles) return 0;
  
-  if (!demuxer->init(this, audio, video, 2097152, 524288))
+  if (!demuxer->init(this, audio, video, 2097152, 524288, subtitles))
   {
     logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
     shutdown();
@@ -90,6 +96,7 @@ int PlayerLiveTV::shutdown()
   initted = false;
 
   delete demuxer;
+  delete subtitles;
 
   return 1;
 }
@@ -114,6 +121,21 @@ void PlayerLiveTV::setAudioChannel(int newChannel, int type)
   return demuxer->setAID(newChannel,type);
 }
 
+bool PlayerLiveTV::toggleSubtitles()
+{
+  if (!subtitlesShowing)
+  {
+    subtitlesShowing = true;
+    subtitles->show();
+  }
+  else
+  {
+    subtitlesShowing = false;
+    subtitles->hide();
+  }
+  return subtitlesShowing;
+}
+
 // ----------------------------------- Externally called events
 
 void PlayerLiveTV::go(ULONG index)
@@ -299,6 +321,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
 
           afeed.start();
           vfeed.start();
+          subtitles->start();
           
           state = newState;
           return;
@@ -329,6 +352,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks(); 
           vfeed.stop();
           afeed.stop();
+          subtitles->stop();
                            
           video->blank();
           video->reset();
@@ -349,6 +373,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
 
           afeed.start();
           vfeed.start();
+          subtitles->start();
           
           state = newState;
           return;
@@ -359,6 +384,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks();
           vfeed.stop();
           afeed.stop();
+          subtitles->stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -393,6 +419,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks();
           vfeed.stop();
           afeed.stop();
+          subtitles->stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -414,6 +441,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
 
           afeed.start();
           vfeed.start();
+          subtitles->start();
 
           state = newState;
           return;
@@ -424,6 +452,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks();
           vfeed.stop();
           afeed.stop();
+          subtitles->stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -451,6 +480,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks();
           vfeed.stop();
           afeed.stop();
+          subtitles->stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -465,6 +495,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks();
           vfeed.stop();
           afeed.stop();
+          subtitles->stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -486,6 +517,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
 
           afeed.start();
           vfeed.start();
+          subtitles->start();
 
           state = newState;
           return;
@@ -580,6 +612,8 @@ void PlayerLiveTV::threadMethod()
           {
             logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
           }
+          if (chan->numSPids > 0)
+            demuxer->setSubID(chan->spids[0].pid);
 
           int streamSuccess = vdr->streamChannel(chan->number, this);
           if (!checkError() && !streamSuccess)
diff --git a/playerlivetv.h b/playerlivetv.h
index 9ddf19d..eb589c7 100644
--- a/playerlivetv.h
+++ b/playerlivetv.h
@@ -49,11 +49,13 @@ class Audio;
 class Video;
 class Log;
 class DemuxerTS;
+class OSDReceiver;
+class DVBSubtitles;
 
 class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver
 {
   public:
-    PlayerLiveTV(MessageQueue* messageQueue, void* messageReceiver, ChannelList* chanList);
+    PlayerLiveTV(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* tosdReceiver, ChannelList* chanList);
     virtual ~PlayerLiveTV();
 
     virtual int init();
@@ -63,6 +65,7 @@ class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, pub
     virtual void setChannel(ULONG index);
     virtual void stop();
     virtual void setAudioChannel(int newChannel,int type);
+    virtual bool toggleSubtitles();
 
     virtual bool* getDemuxerMpegAudioChannels();
     virtual bool* getDemuxerAc3AudioChannels();
@@ -88,12 +91,15 @@ class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, pub
     void threadPostStopCleanup() {};
 
   private:
+    bool subtitlesShowing;
     MessageQueue* messageQueue;
     void* messageReceiver;
+    OSDReceiver* osdReceiver;
     Log* logger;
     Audio* audio;
     Video* video;
     DemuxerTS* demuxer;
+    DVBSubtitles* subtitles;
     VDR* vdr;
     VFeed vfeed;
     AFeed afeed;
diff --git a/vvideolivetv.cc b/vvideolivetv.cc
index 5a7773d..63b3ffa 100644
--- a/vvideolivetv.cc
+++ b/vvideolivetv.cc
@@ -38,6 +38,7 @@
 #include "event.h"
 #include "timers.h"
 #include "vepg.h"
+#include "bitmap.h"
 
 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
 {
@@ -78,7 +79,7 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V
   if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
   {
     streamType = VDR::VIDEO;
-    player = new PlayerLiveTV(Command::getInstance(), this, chanList);
+    player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
   }
   else
   {
@@ -402,6 +403,10 @@ int VVideoLiveTV::handleCommand(int command)
       doEPG();
       return 2;
     }
+    case Remote::RECORD:
+      if (streamType = VDR::VIDEO)
+        (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
+      return 2;
   }
 
   return 1;
@@ -1055,3 +1060,24 @@ void VVideoLiveTV::toggleChopSides()
   }
 }
 
+void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
+{
+  drawBitmap(posX, posY, bm);
+  Region r;
+  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
+  boxstack->update(this, &r);
+}
+
+void VVideoLiveTV::clearOSD()
+{
+  rectangle(area, Colour(0,0,0,0));
+  boxstack->update(this, &area);
+}
+
+void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
+{
+  Region r;
+  r.x = posX; r.y = posY; r.w = width; r.h = height;
+  rectangle(r, Colour(0,0,0,0));
+  boxstack->update(this, &r);
+}
diff --git a/vvideolivetv.h b/vvideolivetv.h
index 78b7339..8057d40 100644
--- a/vvideolivetv.h
+++ b/vvideolivetv.h
@@ -34,6 +34,7 @@
 #include "timerreceiver.h"
 #include "wsymbol.h"
 #include "wprogressbar.h"
+#include "osdreceiver.h"
 
 class VChannelList;
 class Video;
@@ -42,8 +43,9 @@ class BoxStack;
 class WTextbox;
 class PlayerLive;
 class VAudioSelector;
+class Bitmap;
 
-class VVideoLiveTV : public Boxx, public TimerReceiver
+class VVideoLiveTV : public Boxx, public TimerReceiver, public OSDReceiver
 {
   public:
     VVideoLiveTV(ChannelList* chanList, ULONG initialChannelNumber, VChannelList* vchannelList);
@@ -68,6 +70,10 @@ class VVideoLiveTV : public Boxx, public TimerReceiver
 
     void timercall(int ref);
 
+    void drawOSDBitmap(UINT posX, UINT posY, const Bitmap&);
+    void clearOSD();
+    void clearOSDArea(UINT posX, UINT posY, UINT width, UINT height);
+
   private:
     BoxStack* boxstack;
     VDR* vdr;
-- 
2.39.5