]> git.vomp.tv Git - vompclient-marten.git/commitdiff
Teletext
authorChris Tallon <chris@vomp.tv>
Sat, 7 Feb 2009 21:11:09 +0000 (21:11 +0000)
committerChris Tallon <chris@vomp.tv>
Sat, 7 Feb 2009 21:11:09 +0000 (21:11 +0000)
66 files changed:
GNUmakefile
audioplayer.cc
boxstack.cc
boxx.cc
boxx.h
colour.cc
colour.h
defines.h
demuxer.cc
demuxer.h
demuxerts.cc
demuxerts.h
draintarget.h
dssourcepin.cc
localmediafile.h
main.cc
media.cc
media.h
mediafile.cc
mediaplayer.h
mediaprovider.h
message.h
objects.mk
osdwin.cc
player.cc
player.h
playerlive.h
playerliveradio.cc
playerliveradio.h
playerlivetv.cc
playerlivetv.h
playermedia.cc
playerradio.cc
serialize.cc
stream.cc
surface.cc
surface.h
surfacemvp.cc
surfacemvp.h
surfacewin.cc
surfacewin.h
teletextdecodervbiebu.cc [new file with mode: 0644]
teletextdecodervbiebu.h [new file with mode: 0644]
teletxt/COPYING [new file with mode: 0644]
teletxt/README [new file with mode: 0644]
teletxt/tables.h [new file with mode: 0644]
teletxt/txtfont.cc [new file with mode: 0644]
teletxt/txtfont.h [new file with mode: 0644]
tfeed.cc [new file with mode: 0644]
tfeed.h [new file with mode: 0644]
vaudioselector.cc
vaudioselector.h
vfeed.cc
vmedialist.cc
vmediaview.cc
vteletextview.cc [new file with mode: 0644]
vteletextview.h [new file with mode: 0644]
vvideolivetv.cc
vvideolivetv.h
vvideomedia.cc
vvideorec.cc
vvideorec.h
wjpeg.cc
wjpeg.h
wselectlist.cc
wselectlist.h

index c87974476cae1c453b2019561002a46df135efcf..88ad464aff85b8551f3482b3c99031dd1bfb988c 100644 (file)
@@ -6,8 +6,8 @@ CXX=$(CROSS)g++
 LD=$(CROSS)g++
 
 INCLUDES = -I../jpeg/jpeg-6b
-CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -Werror -DDEV -D_GNU_SOURCE $(INCLUDES)
-CXXFLAGS_REL = -O3 -Wall -Wshadow -Werror -D_GNU_SOURCE $(INCLUDES)
+CXXFLAGS_DEV = -g -O0 -Wall -Wshadow -DDEV -D_GNU_SOURCE $(INCLUDES)
+CXXFLAGS_REL = -O3 -Wall -Wshadow  -D_GNU_SOURCE $(INCLUDES)
 LDFLAGS = -Wall -static
 
 LIBPATHS =
index a9824370d2fe6fe92400983d318adee85773c83f..f0930c126cb2a5fb3bf8be863c8b664489086d83 100644 (file)
@@ -74,7 +74,7 @@ AudioPlayer::AudioPlayer(Boxx *parent) : afeed(this)
        uri=NULL;
        demuxer=new DemuxerAudio();
   logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorII");
-       if (!demuxer->init(this, audio, NULL, 0, DemuxerAudio::PACKET_SIZE+200))
+       if (!demuxer->init(this, audio, NULL, NULL, 0, DemuxerAudio::PACKET_SIZE+200,0))
   {
     logger->log("AudioPlayer", Log::ERR, "Demuxer failed to init");
     shutdown();
index 8e183a5924f36f9f24c9c154043466c1a5eec9bd..f7cdbb56cd9ac099cf9b37bc5931fe6bfefd543b 100644 (file)
@@ -72,7 +72,7 @@ int BoxStack::shutdown()
 int BoxStack::add(Boxx* v)
 {
   if (!initted) return 0;
-  
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "add called"); 
 #ifndef WIN32
   pthread_mutex_lock(&boxLock);
 #else
@@ -80,7 +80,16 @@ int BoxStack::add(Boxx* v)
 #endif
   Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for add");  
   
-  if (numBoxes == 16) return 0;
+  if (numBoxes == 16)
+  { //Error
+    Log::getInstance()->log("BoxStack", Log::ERR, "More than 16 boxes! Unlocked for add"); 
+#ifndef WIN32
+    pthread_mutex_unlock(&boxLock);
+#else
+    ReleaseMutex(boxLock);
+#endif
+    return 0;
+  }
   boxes[numBoxes++] = v;
 
 #ifndef WIN32
@@ -215,8 +224,7 @@ void BoxStack::deleteBox(int z)
 
 void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
 {
-//  Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
-  // Get the z index of the box
+  Log::getInstance()->log("BoxStack", Log::DEBUG, "Update called");
 
 #ifndef WIN32
   pthread_mutex_lock(&boxLock);
@@ -225,6 +233,7 @@ void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
 #endif
   Log::getInstance()->log("BoxStack", Log::DEBUG, "Locked for update");
 
+  // Get the z index of the box
   int z;
   for (z = 0; z < numBoxes; z++)
   {
@@ -234,6 +243,13 @@ void BoxStack::update(Boxx* toUpdate, Region* regionToUpdate)
   if (z == numBoxes)
   {
     // not a Box we have!
+#ifndef WIN32
+    pthread_mutex_unlock(&boxLock);
+#else
+    MessageBox(0,"the evil error","error",0);
+    ReleaseMutex(boxLock);
+#endif 
+    Log::getInstance()->log("BoxStack", Log::ERR, "Unlocked for update! box not inside boxstack");
     return;
   }
 
diff --git a/boxx.cc b/boxx.cc
index 1a2621399fc6a7285e068ae463c027265c5ec6cd..81b8878e1d307b87102f0a174a6108b11ed9e0b3 100644 (file)
--- a/boxx.cc
+++ b/boxx.cc
@@ -346,20 +346,33 @@ void Boxx::drawTextCentre(const char* text, int x, int y, const Colour& colour)
   else surface->drawTextCentre(text, x, y, colour.rgba());
 }
 
-void Boxx::drawPixel(UINT x, UINT y, const Colour& colour)
+void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw)
 {
-  if (parent) parent->drawPixel(area.x + x, area.y + y, colour);
+  if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw);
   else
   {
-    int c = (  (0xFF000000         )
+    int c = (  (colour.alpha << 24 )
              | (colour.red    << 16)
              | (colour.green  <<  8)
              | (colour.blue        ) );
 
-    surface->drawPixel(x, y, c);
+    surface->drawPixel(x, y, c,fastdraw);
   }
 }
 
+void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw)
+{
+  if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw);
+  else
+  {
+    int c = (  (0xFF000000         )
+             | (colour.red    << 16)
+             | (colour.green  <<  8)
+             | (colour.blue        ) );
+
+    surface->drawPixel(x, y, c,fastdraw);
+  }
+}
 void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm)
 {
   if (parent) parent->drawBitmap(area.x + x, area.y + y, bm);
diff --git a/boxx.h b/boxx.h
index d5eb7c1742e2e7b75d7016d7ea2465926b8006c3..0e7a4b93fdf57b1f31ac5759849a0c505b603238 100644 (file)
--- a/boxx.h
+++ b/boxx.h
@@ -102,8 +102,9 @@ class Boxx
     void drawText(const char* text, int x, int y, int width, const Colour& colour);
     void drawTextRJ(const char* text, int x, int y, const Colour& colour);
     void drawTextCentre(const char* text, int x, int y, const Colour& colour);
-    void drawPixel(UINT x, UINT y, const Colour& colour);
+    void drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw=false);
     void drawBitmap(UINT x, UINT y, const Bitmap& bm);
+    void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false);
 
     /* This is for system which need a locking of the drawing surface to speed up drawing */
     void startFastDraw();
index 7d309e8b473308352f0a2603a61874f465ec180d..f1b8f68beb37a2e40d739bbcf044f6b98e8098bf 100644 (file)
--- a/colour.cc
+++ b/colour.cc
@@ -33,6 +33,7 @@ Colour Colour::VIEWBACKGROUND(0, 0, 100);
 Colour Colour::TABVIEWBACKGROUND(0, 0, 120);
 Colour Colour::TITLEBARBACKGROUND(0, 0, 200);
 Colour Colour::SELECTHIGHLIGHT(240, 250, 80);
+Colour Colour::SELECTDARKHIGHLIGHT(120, 125, 40);
 Colour Colour::LIGHTTEXT(255, 255, 255);
 Colour Colour::DARKTEXT(0, 0, 100);
 Colour Colour::DANGER(200, 0, 0);
index 58d0664e3c1a69cc78d01c83f15da0aa56c57962..9c9687cb7d47084b5812e60d79f9e445ba9cc40a 100644 (file)
--- a/colour.h
+++ b/colour.h
@@ -59,6 +59,7 @@ class Colour
     static Colour TABVIEWBACKGROUND;
     static Colour TITLEBARBACKGROUND;
     static Colour SELECTHIGHLIGHT;
+    static Colour SELECTDARKHIGHLIGHT;
     static Colour LIGHTTEXT;
     static Colour DARKTEXT;
     static Colour DANGER;
index b4003049c9db2055f10c61bcc505200f05edd93b..9f5815ef6f2483a7d9ab771501934fd8a96191ff 100644 (file)
--- a/defines.h
+++ b/defines.h
@@ -51,7 +51,8 @@ void MILLISLEEP(ULONG a);
 #else
 
   int max(int, int);
-
+  int min(UINT, int);
+  
   #define Surface_TYPE SurfaceMVP
   #define Thread_TYPE ThreadP
   #include <pthread.h>
index 398a737d21c226015b1c18fb1c1c24e4a4f68e64..054baca7ab953b11dfc88acf2d76294b877cbfd6 100644 (file)
@@ -207,12 +207,14 @@ Demuxer* Demuxer::getInstance()
   return instance;
 }
 
-int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, ULONG demuxMemoryV, ULONG demuxMemoryA, DVBSubtitles* tsubtitles)
+int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,
+                  ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT, DVBSubtitles* tsubtitles)
 {
   if (!initted)
   {
     if ( !videostream.init(video, demuxMemoryV) ||
-         !audiostream.init(audio, demuxMemoryA))
+         !audiostream.init(audio, demuxMemoryA) ||
+         !teletextstream.init(teletext, demuxMemoryT))
     {
       Log::getInstance()->log("Demuxer", Log::CRIT,
                               "Failed to initialize demuxer");
@@ -220,6 +222,11 @@ int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, U
       return 0;
     }
   }
+  if (teletext) {
+      isteletextdecoded = true;
+  } else {
+      isteletextdecoded = false;
+  }
 
   reset();
   initted = true;
@@ -232,7 +239,7 @@ void Demuxer::reset()
 {
   Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");
   flush();
-  video_current = audio_current = -1;
+  video_current = audio_current = teletext_current = subtitle_current = -1;
   horizontal_size = vertical_size = 0;
   aspect_ratio = (enum AspectRatio) 0;
   frame_rate = bit_rate = 0;
@@ -246,12 +253,17 @@ void Demuxer::reset()
   {
     avail_ac3audchan[i] = false;
   }
+  for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)
+  {
+    avail_dvbsubtitlechan[i] = false;
+  }
 }
 
 int Demuxer::shutdown()
 {
   videostream.shutdown();
   audiostream.shutdown();
+  teletextstream.shutdown();
   initted = false;
   return 1;
 }
@@ -262,6 +274,7 @@ void Demuxer::flush()
 
   videostream.flush();
   audiostream.flush();
+  teletextstream.flush();
 }
 
 void Demuxer::flushAudio()
@@ -272,7 +285,7 @@ void Demuxer::flushAudio()
 void Demuxer::seek()
 {
   vid_seeking = aud_seeking = true;
-  video_pts = audio_pts = 0;
+  video_pts = audio_pts = teletext_pts = 0;
 }
 
 void Demuxer::setAudioStream(int id)
@@ -285,6 +298,16 @@ void Demuxer::setVideoStream(int id)
   video_current = id;
 }
 
+void Demuxer::setTeletextStream(int id)
+{
+  teletext_current = id;
+}
+
+void Demuxer::setDVBSubtitleStream(int id)
+{
+  subtitle_current = id;
+}
+
 void Demuxer::setAspectRatio(enum AspectRatio ar)
 {
   if (aspect_ratio != ar)
@@ -312,6 +335,11 @@ bool Demuxer::writeVideo()
   return videostream.drain();
 }
 
+bool Demuxer::writeTeletext()
+{
+   return teletextstream.drain();
+}
+
 bool Demuxer::submitPacket(PESPacket& packet)
 {
   UINT sent = 0;
@@ -350,11 +378,32 @@ bool Demuxer::submitPacket(PESPacket& packet)
     }
   }
   else if (packet_type == PESTYPE_PRIVATE_1 &&
-           packet.getSubstream() == 0x20)
+           packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&
+           packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)
   {
-    if (subtitles) subtitles->put(packet);
+    avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;
+    if (subtitle_current == -1) subtitle_current = packet.getSubstream();
+    if (subtitles && packet.getSubstream()==subtitle_current)
+    {
+         subtitles->put(packet);
+    }
     sent = packet.getSize();
   }
+  else if (isteletextdecoded  && packet_type == PESTYPE_PRIVATE_1 &&
+           packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&
+           packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)
+  {
+
+    if (teletext_current == -1) teletext_current = packet.getSubstream();
+    if (teletext_current == packet.getSubstream() )
+    {
+        sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT);
+    }
+    else 
+    {
+        sent = packet.getSize();
+    }
+  }
   else
   {
     sent = packet.getSize();
@@ -435,6 +484,14 @@ pre_1_3_19_Recording: //This is for old recordings stuff and live TV
           }
         }
         break;
+      case 0x10: //Teletext Is this correct?
+          packet.setSubstream(substream_id);
+          // Extract teletxt PTS if it exists
+        if (packet.hasPTS())
+        {
+          teletext_pts = packet.getPTS();
+        }
+        break;
       default:
         if (!ispre_1_3_19)
         {
@@ -540,12 +597,19 @@ bool* Demuxer::getac3AudioChannels()
   return avail_ac3audchan;
 }
 
-int Demuxer::getselAudioChannel()
+bool* Demuxer::getSubtitleChannels()
 {
-  return audio_current;
+  return avail_dvbsubtitlechan;
+}
+
+int Demuxer::getselSubtitleChannel()
+{
+  return subtitle_current;
 }
 
-void Demuxer::setAudioChannel(int aud_channel)
+int Demuxer::getselAudioChannel()
 {
-  audio_current = aud_channel;
+  return audio_current;
 }
+
+
index db5a8a6f4ec36e99bceafdba9e6b2ddf36ba5a68..bef9e79458327ee85defab59f60de48bedd6f01d 100644 (file)
--- a/demuxer.h
+++ b/demuxer.h
@@ -79,15 +79,21 @@ class Demuxer
     Demuxer();
     virtual ~Demuxer();
     static Demuxer* getInstance();
-    int init(Callback* callback, DrainTarget* audio, DrainTarget* video, ULONG demuxMemoryV, ULONG demuxMemoryA, DVBSubtitles* tsubtitles = NULL);
+     int init(Callback* tcallback, DrainTarget* audio, DrainTarget* video,
+         DrainTarget* teletext,
+         ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,
+         DVBSubtitles* tsubtitles=NULL);
     virtual void reset();
     virtual void flush();
     void flushAudio();
     void seek();
     void setVideoStream(int id);
     void setAudioStream(int id);
+    void setTeletextStream(int id);
+    void setDVBSubtitleStream(int id);
     bool writeAudio();
     bool writeVideo();
+    bool writeTeletext();
 
     virtual int scan(UCHAR* buf, int len) = 0;
     virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0;
@@ -99,8 +105,9 @@ class Demuxer
 
     bool* getmpAudioChannels(); //Maybe virtual ?
     bool* getac3AudioChannels(); //Maybe virtual ?
+    bool* getSubtitleChannels();
     int getselAudioChannel();
-    void setAudioChannel(int aud_channel);
+    int getselSubtitleChannel();
 
     int getHorizontalSize() { return horizontal_size; }
     int getVerticalSize() { return vertical_size; }
@@ -150,6 +157,18 @@ class Demuxer
     };
     enum PESTYPE_SUBSTREAM
     {
+      PESTYPE_SUBSTREAM_TELETEXT0 = 0x10,
+      PESTYPE_SUBSTREAM_TELETEXT1,PESTYPE_SUBSTREAM_TELETEXT2, PESTYPE_SUBSTREAM_TELETEXT3,
+      PESTYPE_SUBSTREAM_TELETEXT4,PESTYPE_SUBSTREAM_TELETEXT5,PESTYPE_SUBSTREAM_TELETEXT6,
+      PESTYPE_SUBSTREAM_TELETEXT7, PESTYPE_SUBSTREAM_TELETEXT8, PESTYPE_SUBSTREAM_TELETEXT9,
+      PESTYPE_SUBSTREAM_TELETEXT10,PESTYPE_SUBSTREAM_TELETEXT11,PESTYPE_SUBSTREAM_TELETEXT12,
+      PESTYPE_SUBSTREAM_TELETEXT13,PESTYPE_SUBSTREAM_TELETEXT14,PESTYPE_SUBSTREAM_TELETEXT15,
+      PESTYPE_SUBSTREAM_TELETEXTMAX=PESTYPE_SUBSTREAM_TELETEXT15,
+      PESTYPE_SUBSTREAM_DVBSUBTITLE0=0x20,
+      PESTYPE_SUBSTREAM_DVBSUBTITLE1,PESTYPE_SUBSTREAM_DVBSUBTITLE2,PESTYPE_SUBSTREAM_DVBSUBTITLE3,
+      PESTYPE_SUBSTREAM_DVBSUBTITLE4,PESTYPE_SUBSTREAM_DVBSUBTITLE5,PESTYPE_SUBSTREAM_DVBSUBTITLE6,
+      PESTYPE_SUBSTREAM_DVBSUBTITLE7,
+      PESTYPE_SUBSTREAM_DVBSUBTITLEMAX=PESTYPE_SUBSTREAM_DVBSUBTITLE7,
       PESTYPE_SUBSTREAM_AC30 = 0x80,
       PESTYPE_SUBSTREAM_AC31,PESTYPE_SUBSTREAM_AC32, PESTYPE_SUBSTREAM_AC33,
       PESTYPE_SUBSTREAM_AC34,PESTYPE_SUBSTREAM_AC35,PESTYPE_SUBSTREAM_AC36,
@@ -167,11 +186,12 @@ class Demuxer
     Stream videostream;
     Stream audiostream;
     DVBSubtitles* subtitles;
+    Stream teletextstream;
     int shutdown();
     bool initted;
     bool vid_seeking;
     bool aud_seeking;
-    int video_current, audio_current;
+    int video_current, audio_current, teletext_current, subtitle_current;
 
     // Video stream information
     void setAspectRatio(enum AspectRatio);
@@ -186,6 +206,8 @@ class Demuxer
     ULLONG video_pts;
     ULLONG video_pts_seek;
     ULLONG audio_pts;
+    ULLONG teletext_pts;
+    bool isteletextdecoded;
 
     // Constants
     static const int FrameRates[9];
@@ -193,6 +215,7 @@ class Demuxer
     bool ispre_1_3_19;
     bool avail_mpaudchan[PESTYPE_AUDMAX-PESTYPE_AUD0+1];
     bool avail_ac3audchan[PESTYPE_SUBSTREAM_AC3MAX-PESTYPE_SUBSTREAM_AC30+1];
+    bool avail_dvbsubtitlechan[PESTYPE_SUBSTREAM_DVBSUBTITLEMAX-PESTYPE_SUBSTREAM_DVBSUBTITLE0+1];
 };
 
 #endif
index 03c6a9c0bd173b3cce61aa4bed44affaa1ddf5ae..c60f4b0675e9c95d0fa4b074e46444a5aea8533f 100644 (file)
 #include "demuxerts.h"
 #include "log.h"
 
-DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID)
+DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)
 {
   vID = p_vID; vActive = false;
   aID = p_aID; aActive = false;
   subID = p_subID; subActive = false;
   atype = 0;
   subLength = 0;
+  tID = p_tID;
 }
 
 void DemuxerTS::flush()
@@ -47,10 +48,13 @@ void DemuxerTS::flush()
     break;
   }
   subPacket.init(PESTYPE_PRIVATE_1);
+tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
+
   vActive = false;
   aActive = false;
   subActive = false;
   subLength = 0;
+  tActive = false;
 }
 
 int DemuxerTS::scan(UCHAR *buf, int len)
@@ -99,6 +103,14 @@ void DemuxerTS::setSubID(int p_subID)
   subLength = 0;
 }
 
+void DemuxerTS::setTID(int p_tID)
+{
+  tID = p_tID;
+  tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
+  tActive = false;
+
+}
+
 int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
 {
   UINT LoPattern = 0x100 | PESTYPE_VID0,
@@ -267,7 +279,19 @@ int DemuxerTS::processTS(UCHAR* buf)
       }
       subActive = true;
     }
-        
+    if (isteletextdecoded && pid == tID)
+    {
+      if (tActive)
+      {
+        if (!parsed)
+        {
+          parsePacketDetails(tPacket);
+          parsed = true;
+        }
+      rc = submitPacket(tPacket);
+      }
+      tActive = true;
+    }
     if (rc == 0) return 0;
 
     parsed = false;
@@ -296,16 +320,28 @@ int DemuxerTS::processTS(UCHAR* buf)
       subLength = (buf[4] << 8) + buf[5];
       buf += 6; datalen -= 6;
     }
+    if (isteletextdecoded && pid == tID)
+    {
+        tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
+      buf += 6; datalen -= 6;
+    }
   }
 
   if ( (pid == vID && vActive) ||
        (pid == aID && aActive) ||
+       (pid == tID && tActive) ||
        (pid == subID && subActive) )
   {
     PESPacket* packet = NULL;
     if (pid == vID) packet = &vPacket;
     if (pid == aID) packet = &aPacket;
-    if (pid == subID) packet = &subPacket;
+    if (pid == subID) {
+#ifdef WIN32
+        MessageBox(0,"sub","usb",0);
+#endif
+        packet = &subPacket;
+    }
+    if (pid == tID) packet = &tPacket;
     if (packet != NULL)
     {
       if (packet->write(buf, datalen) == 0)
index 0df7cd641f8d3359f4c6246cc96be8b5715c676a..e1f19237916f129069dfb0848e18186d9f407d19 100644 (file)
 class DemuxerTS : public Demuxer
 {
   public:
-    DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0);
+    DemuxerTS(int p_vID = 0, int p_aID = 0, int p_subID = 0, int p_tID = 0);    
     void flush();
     int scan(UCHAR* buf, int len);
     int findPTS(UCHAR* buf, int len, ULLONG* dest);
     void setVID(int p_vID);
+    void setTID(int p_tID);
     void setAID(int p_aID, int type);
     void setSubID(int p_subID);
     int  getVID() { return vID; }
+    int  getTID() { return tID; }
     int  getAID() { return aID; }
     int  getSubID() { return subID; }
     int put(UCHAR* buf, int len);
@@ -51,11 +53,13 @@ class DemuxerTS : public Demuxer
     PESPacket vPacket; // Video PES packet under construction
     PESPacket aPacket; // Audio PES packet under construction
     PESPacket subPacket; // Subtitles PES packet under construction
-    int vID, aID, subID; // TS IDs for video/audio/subtitles
+    PESPacket tPacket; // Teletext PES packet under construction
+    int vID, aID, subID,tID; // 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
+ UINT subLength;        // Expected length of subtitle packet   
+bool vActive, aActive, tActive; // Whether video/audio is actively being captured
 };
 
 #endif
index 751e551c590237b29115caadcfd5124b11247e25..4c73612eefc292458e1df6a4acc464856c291165 100644 (file)
@@ -29,6 +29,7 @@
 #define MPTYPE_AC3 0x02
 #define MPTYPE_AC3_PRE13 0x03 //old vdr recording compatmode
 #define MPTYPE_MPEG_AUDIO_LAYER3 0x04 //for media mp3 playback
+#define MPTYPE_TELETEXT 0x05 //for EBU VBI teletext
 
 struct MediaPacket
 {
@@ -36,11 +37,11 @@ struct MediaPacket
   ULONG length; //length of the packet
   // The fields below are not needed by the MVP
   UCHAR type;
+  ULLONG pts;
+  bool synched;
 #ifdef WIN32
   ULLONG recording_byte_pos; //position in recording
-  ULLONG pts;
   long long presentation_time;/* in 100 ns units*/
-  bool synched;
   bool disconti;
 #endif
 };
index cd6049d4e7c1e783c54f418655d8f3cc3e1c8c2a..d5aa13ac3404b555be5c662261d2ab3ce4f2b9b2 100644 (file)
@@ -717,7 +717,7 @@ HRESULT DsSourcePin::GetMediaTypeAc3(int iPosition, AM_MEDIA_TYPE *pmt)
                  wfe.wFormatTag = WAVE_FORMAT_UNKNOWN;
                  wfe.wBitsPerSample = 0;
                  pmt->subtype = MEDIASUBTYPE_DOLBY_AC3;
-         // pmt->subtype = MEDIASUBTYPE_DOLBY_AC3_SPDIF;
+        //  pmt->subtype = MEDIASUBTYPE_DOLBY_AC3_SPDIF;
                  pmt->formattype = FORMAT_WaveFormatEx;
                  pmt->cbFormat = sizeof(wfe);
                  pmt->pbFormat = (BYTE*)CoTaskMemAlloc(sizeof(wfe));
index b83ee7626287952a382db2fc1289310108dac08c..6da202e00ac0173928b2f2bd51b9509d5d5d1d90 100644 (file)
 #include "media.h"
 #include <sys/stat.h>
 #include <sys/types.h>
+#ifndef WIN32
 #include <dirent.h>
+#else
+
+#endif
 #include <iostream>
 #include "log.h"
 
diff --git a/main.cc b/main.cc
index ac5a5936780fb6a959ddf4befae560ad8d841222..fee721473632bc5bebd0ff8ec36b25a19ac42ca1 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -520,8 +520,15 @@ void MILLISLEEP(ULONG a)
 #endif
 }
 
+int min(UINT a, int b)
+{
+  if (a > b) return b;
+  else return a;
+}
+
 int max(int a, int b)
 {
   if (a > b) return a;
   else return b;
 }
+
index ec036f990ca6775d98bdad6eda79b0c87ba23460..6361585fec6e5b415b7cbc8ac926fc5c5472841b 100644 (file)
--- a/media.cc
+++ b/media.cc
@@ -20,7 +20,9 @@
 
 #include "media.h"
 #include <time.h>
+#ifndef WIN32
 #include <arpa/inet.h>
+#endif
 #ifndef SNPRINTF
 #define SNPRINTF snprintf
 #endif
diff --git a/media.h b/media.h
index b2b37f88f13dc315093619d2b7d4d5152537fdc8..7ad052271d573583d7a48c870acdfd1fe678f64b 100644 (file)
--- a/media.h
+++ b/media.h
@@ -21,8 +21,9 @@
 #ifndef MEDIA_H
 #define MEDIA_H
 
-using namespace std;
+
 #include <vector>
+using namespace std;
 #include <stdio.h>
 #include <string.h>
 #include "defines.h"
index 2e558dc852d9c0ad6df3b7cb7fb9650fb75035e6..d01f1aeadb3da35657dd8ca640cebc326e1a6df1 100644 (file)
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
 
+#ifndef WIN32
+#include <dirent.h>
+#else
+#include "threadwin.h"
+#include <io.h>
+#endif
+
 #include "mediafile.h"
 #include "media.h"
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <dirent.h>
+
 #include <iostream>
 #include "log.h"
 
@@ -83,10 +90,12 @@ ULONG MediaFile::getMediaType(const char * filename) {
 
 Media * MediaFile::createMedia(const char * dirname, const char * filename, bool withURI) {
   Media * rt=NULL;
-  char *buffer;
-  asprintf(&buffer, "%s/%s", dirname, filename);
-  struct stat st;
+  char *buffer=(char*)malloc(strlen(dirname)+strlen(filename)+2);
+  sprintf(buffer, "%s/%s", dirname, filename);
+
   ULONG mtype=MEDIA_TYPE_UNKNOWN;
+#ifndef WIN32
+  struct stat st;
   if (stat(buffer, &st) == 0) {
     if (S_ISDIR(st.st_mode)) {
        mtype=MEDIA_TYPE_DIR;
@@ -95,12 +104,29 @@ Media * MediaFile::createMedia(const char * dirname, const char * filename, bool
        mtype=getMediaType(filename);
     }
   }
+#else 
+  WIN32_FILE_ATTRIBUTE_DATA att;
+  GetFileAttributesEx(buffer,GetFileExInfoStandard,&att);
+  if (att.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {    
+       mtype=MEDIA_TYPE_DIR;
+  } else {
+       mtype=getMediaType(filename);
+  }
+#endif
+
   //only consider entries we accept by type here
   if (mtype != MEDIA_TYPE_UNKNOWN) {
     rt =new Media();
     rt->setMediaType(mtype);
     rt->setFileName(filename);
+#ifndef WIN32
     rt->setTime(st.st_mtime);
+#else
+    struct timespec targetTime;
+    targetTime.tv_sec=(*((__int64*) &att.ftCreationTime)-WINDOWS_TIME_BASE_OFFSET)/(10*1000*1000);
+    targetTime.tv_nsec=((*((__int64*)&att.ftCreationTime)-WINDOWS_TIME_BASE_OFFSET)%(10*1000*1000))*100;
+    rt->setTime(targetTime.tv_sec);
+#endif
     Log::getInstance()->log("Media",Log::DEBUG,"created Media %s, type=%d",filename,mtype);
     if (withURI) {
       MediaURI u(providerid,buffer,NULL);
@@ -118,15 +144,25 @@ MediaList* MediaFile::getMediaList(const MediaURI * parent){
   rt=new MediaList(parent);
   const char *dirname=parent->getName();
   //open the directory and read out the entries
+#ifndef WIN32
   DIR *d=opendir(dirname);
   struct dirent *e;
   union { // according to "The GNU C Library Reference Manual"
     struct dirent d;
     char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
     } u;
-
   while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) {
-    const char * fname=e->d_name;
+      const char * fname=e->d_name;
+#else
+  WIN32_FIND_DATA  e;
+  HANDLE d;
+  d=FindFirstFile(dirname,&e);
+  if (d==INVALID_HANDLE_VALUE) {
+      return rt;
+  }
+  do  {
+      const char * fname=e.cFileName;
+#endif    
     if ( fname == NULL) continue;
     if (strcmp(fname,".") == 0) continue;
     if (strcmp(fname,"..") == 0) continue;
@@ -138,10 +174,15 @@ MediaList* MediaFile::getMediaList(const MediaURI * parent){
     else {
       if (m) delete m;
     }
+#ifndef WIN32
   }
   if (d != NULL) closedir(d);
+#else
+  } while (FindNextFile(d,&e));
+  FindClose(d);
+#endif
   return rt;
-  }
+}
 
 
 int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize) {
@@ -155,9 +196,14 @@ int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, UL
     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
     return -1;
   }
-  struct stat st;
+  
   ULLONG mysize=0;
+#ifndef WIN32 
+  struct stat st;
   if ( fstat(fileno(fp),&st) == 0) mysize=st.st_size;
+#else 
+  mysize=_filelength(_fileno(fp));
+#endif
   if (mysize == 0) {
     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
     fclose(fp);
index c3dfcf2fae7a4f787d8c3a512944b01743df76c6..ada5c9704220ca4271051b201d66407710e59e91 100644 (file)
@@ -21,8 +21,9 @@
 #ifndef MEDIAPLAYER
 #define MEDIAPLAYER
 
-using namespace std;
+
 #include <vector>
+using namespace std;
 #include <stdio.h>
 #include <string.h>
 #include "mediaprovider.h"
index 04c17b7fb3034d8c233f9c7e7aa5dccfab243308..f5b1e94500eeec56145613ea02f5998cd75c81a5 100644 (file)
 
 #include <stdio.h>
 #include <string.h>
+#ifndef WIN32
 #include <arpa/inet.h>
+#else
+
+#endif
+
 #include "defines.h"
 
 class Media;
index 0c50be418d4527a3e4c78042c82d679045c99821..7d5d794c7e7682b249cb9025ca793e02f3b5105e 100644 (file)
--- a/message.h
+++ b/message.h
@@ -71,6 +71,9 @@ class Message
     const static ULONG CHANGED_REMOTECONTROL = 29;
     const static ULONG DELETE_SELECTED_TIMER = 30;
     const static ULONG CHANGED_DEVICEOPTIONS = 31;
+    const static ULONG TELETEXTUPDATE = 32;
+    const static ULONG TELETEXTUPDATEFIRSTLINE = 33;
+    const static ULONG SUBTITLE_CHANGE_CHANNEL = 34;
 };
 
 #endif
index ad2727e20759af677f3150d23b7b4df78b3b2769..f7243066929bed7c5d5292540841cd84e213e9c8 100644 (file)
@@ -23,5 +23,6 @@ OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o
            bitmap.o dvbsubtitles.o                                               \
            imagereader.o vcolourtuner.o mediaoptions.o mediaplayer.o mediafile.o \
            serialize.o localmediafile.o vmediaview.o vvideomedia.o playermedia.o \
-           demuxermedia.o
+           demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o        \
+           teletxt/txtfont.o
 
index bf829b3f594fd6d4b34172b264adec0c3c20e127..aff35f73bced274e154a6ba8f17bdfbe5d02bdb1 100644 (file)
--- a/osdwin.cc
+++ b/osdwin.cc
@@ -231,7 +231,7 @@ void OsdWin::Render()
 }
 
 void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){
-       if (!initted) return;
+       if (!initted) return; 
        if (external_driving) {
                InternalRendering(present);
         lastrendertime=timeGetTime();
index 774cda9ce48eed7af2d01d26ebf7ee8f067a2972..9400d0e788bcfc3070043ba730e489ce80ce0479 100644 (file)
--- a/player.cc
+++ b/player.cc
@@ -37,7 +37,7 @@
 // ----------------------------------- Called from outside, one offs or info funcs
 
 Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)
-: vfeed(this), afeed(this)
+: vfeed(this), afeed(this), tfeed(this)
 {
   messageQueue = tmessageQueue;
   messageReceiver = tmessageReceiver;
@@ -82,7 +82,11 @@ int Player::init()
   subtitles = new DVBSubtitles(osdReceiver);
   if (!subtitles) return 0;
 
-  if (!demuxer->init(this, audio, video, 2097152, 524288, subtitles))
+  teletext = new TeletextDecoderVBIEBU();
+  if (!teletext) return 0;
+  teletext->setRecordigMode(true);
+  if (!demuxer->init(this, audio, video,teletext, 2097152, 524288,65536, subtitles))
   {
     logger->log("Player", Log::ERR, "Demuxer failed to init");
     shutdown();
@@ -91,6 +95,7 @@ int Player::init()
 
   vfeed.init();
   afeed.init();
+  tfeed.init();
 
   video->stop();
   video->blank();
@@ -110,6 +115,8 @@ int Player::shutdown()
   demuxer = NULL;
   delete subtitles;
   subtitles = NULL;
+  delete teletext;
+  teletext = NULL;
 
 #ifdef WIN32
   CloseHandle(mutex);
@@ -167,14 +174,34 @@ bool* Player::getDemuxerAc3AudioChannels()
   return demuxer->getac3AudioChannels();
 }
 
+bool* Player::getDemuxerSubtitleChannels()
+{
+  return demuxer->getSubtitleChannels();
+}
+
 int Player::getCurrentAudioChannel()
 {
     return demuxer->getselAudioChannel();
 }
 
+int Player::getCurrentSubtitleChannel()
+{
+    return demuxer->getselSubtitleChannel();
+}
+
+void Player::setSubtitleChannel(int newChannel)
+{
+  return demuxer->setDVBSubtitleStream(newChannel);
+}
+
+int *Player::getTeletxtSubtitlePages()
+{
+    return teletext->getSubtitlePages();
+}
+
 void Player::setAudioChannel(int newChannel, int type)
 {
-    demuxer->setAudioChannel(newChannel);
+    demuxer->setAudioStream(newChannel);
 }
 
 bool Player::toggleSubtitles()
@@ -192,6 +219,20 @@ bool Player::toggleSubtitles()
   return subtitlesShowing;
 }
 
+void  Player::turnSubtitlesOn(bool ison) {
+ if (ison)
+  {
+    subtitlesShowing = true;
+    subtitles->show();
+  }
+  else
+  {
+    subtitlesShowing = false;
+    subtitles->hide();
+  }
+
+}
+
 // ----------------------------------- Externally called events
 
 void Player::play()
@@ -371,6 +412,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           threadStop();
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           demuxer->flush();
           state = S_FFWD;
@@ -384,6 +426,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           threadStop();
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           demuxer->flush();
           state = S_FBWD;
@@ -394,6 +437,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
         {
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           threadStop();
           video->stop();
@@ -416,6 +460,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           threadStop();
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           demuxer->flush();
           state = S_PAUSE_I;
@@ -451,6 +496,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           audio->systemMuteOn();
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           threadStop();
           video->unPause();
@@ -465,6 +511,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           audio->systemMuteOn();
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           threadStop();
           video->unPause();
@@ -477,6 +524,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
         {
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           threadStop();
           video->stop();
@@ -504,6 +552,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           threadStop();
           vfeed.stop();
           afeed.stop();
+          tfeed.stop();
           subtitles->stop();
           demuxer->flush();
           state = S_PAUSE_I;
@@ -712,6 +761,7 @@ void Player::switchState(UCHAR toState, ULONG jumpFrame)
           logger->log("Player", Log::DEBUG, "Immediate play");
           afeed.start();
           vfeed.start();
+          tfeed.start();
           subtitles->start();
           video->sync();
           audio->sync();
@@ -781,6 +831,7 @@ void Player::restartAtFrame(ULONG newFrame)
 {
   vfeed.stop();
   afeed.stop();
+  tfeed.stop();
   subtitles->stop();
   threadStop();
   video->stop();
@@ -793,6 +844,7 @@ void Player::restartAtFrame(ULONG newFrame)
   demuxer->setFrameNum(newFrame);
   videoStartup = true;
   afeed.start();
+  tfeed.start();
   vfeed.start();
   subtitles->start();
   threadStart();
@@ -943,6 +995,7 @@ void Player::threadMethod()
     demuxer->setFrameNum(currentFrameNumber);
     videoStartup = true;
     afeed.start();
+    tfeed.start();
     vfeed.start();
     subtitles->start();
     audio->play();
index b009956b7a11f723be66dc119289c126829816bc..3db0a11d5b641efcc67a8e72cc07c19e72bc024d 100644 (file)
--- a/player.h
+++ b/player.h
@@ -38,6 +38,9 @@
 #include "defines.h"
 #include "vfeed.h"
 #include "afeed.h"
+#include "tfeed.h"
+
+#include "teletextdecodervbiebu.h"
 
 class MessageQueue;
 class Audio;
@@ -60,7 +63,10 @@ class Player : public Thread_TYPE, public Callback
     void setLengthBytes(ULLONG length);
     void setLengthFrames(ULONG length);
     void setAudioChannel(int newChannel, int type);
+    void setSubtitleChannel(int newChannel);
     bool toggleSubtitles();
+    void turnSubtitlesOn(bool ison); 
+    bool isSubtitlesOn() {return subtitlesShowing;};
 
     void play();
     void stop();
@@ -79,7 +85,12 @@ class Player : public Thread_TYPE, public Callback
     UCHAR getIScanRate() { return ifactor; }
     bool* getDemuxerMpegAudioChannels();
     bool* getDemuxerAc3AudioChannels();
+    bool* getDemuxerSubtitleChannels();
+    int *getTeletxtSubtitlePages();
     int getCurrentAudioChannel();
+    int getCurrentSubtitleChannel();
+
+   TeletextDecoderVBIEBU * getTeletextDecoder(){return teletext;};
 
     void call(void*); // for callback interface
 
@@ -133,6 +144,10 @@ class Player : public Thread_TYPE, public Callback
     VDR* vdr;
     VFeed vfeed;
     AFeed afeed;
+    TFeed tfeed;
+    TeletextDecoderVBIEBU *teletext;
+  
+    
 
     bool initted;
     bool startup;
index 88beca299e2a8f8453af0adf910deb94def2868d..601ddefa5878c99c24b653caf3468bed0f8ae7c6 100644 (file)
@@ -47,10 +47,13 @@ class PlayerLive
     virtual void setChannel(ULONG index)=0;
     virtual void stop()=0;
     virtual void setAudioChannel(int newChannel,int type)=0;
+    virtual void setSubtitleChannel(int newChannel)=0;
 
     virtual bool* getDemuxerMpegAudioChannels()=0;
     virtual bool* getDemuxerAc3AudioChannels()=0;
     virtual int getCurrentAudioChannel()=0;
+    virtual int getCurrentSubtitleChannel()=0;
+    virtual int *getTeletxtSubtitlePages()=0;
 };
 
 #endif
index e4a5f38c585e0af6d921723bc845563a4b0cf32b..6b6f35f40c9414210cd0fb5288f2ece2623d044b 100644 (file)
@@ -61,7 +61,7 @@ int PlayerLiveRadio::init()
   demuxer = new DemuxerTS();
   if (!demuxer) return 0;
  
-  if (!demuxer->init(this, audio, NULL, 0, 200000))
+  if (!demuxer->init(this, audio, NULL, NULL, 0, 200000,0))
   {
     logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
     shutdown();
@@ -103,11 +103,24 @@ int PlayerLiveRadio::getCurrentAudioChannel()
   return demuxer->getAID();
 }
 
+int *PlayerLiveRadio::getTeletxtSubtitlePages(){
+    return NULL;
+}
+
+int PlayerLiveRadio::getCurrentSubtitleChannel(){
+    return demuxer->getSubID();
+}
+
 void PlayerLiveRadio::setAudioChannel(int newChannel, int type)
 {
   return demuxer->setAID(newChannel, type);
 }
 
+void PlayerLiveRadio::setSubtitleChannel(int newChannel)
+{
+  return demuxer->setSubID(newChannel);
+}
+
 // ----------------------------------- Externally called events
 
 void PlayerLiveRadio::go(ULONG index)
index 9f6aee3be62a80eda12927883b5dc34f11abff9c..9a3865a93b137a27ce7b5a8c8251424864629a88 100644 (file)
@@ -61,10 +61,13 @@ class PlayerLiveRadio : public PlayerLive, public Thread_TYPE, public Callback,
     virtual void setChannel(ULONG index);
     virtual void stop();
     virtual void setAudioChannel(int newChannel, int type);
+    virtual void setSubtitleChannel(int newChannel);
 
     virtual bool* getDemuxerMpegAudioChannels();
     virtual bool* getDemuxerAc3AudioChannels();
     virtual int getCurrentAudioChannel();
+    virtual int *getTeletxtSubtitlePages();
+    virtual int getCurrentSubtitleChannel();
 
     void call(void*); // for callback interface
 
index 5df0680626e8d8875cb9ea8731dbbb4e782e6b2d..47972befb7e699b25e75a7766be33770c8ba52e7 100644 (file)
@@ -35,7 +35,7 @@
 // ----------------------------------- Called from outside, one offs or info funcs
 
 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
-: vfeed(this), afeed(this)
+: vfeed(this), afeed(this), tfeed(this)
 {
   messageQueue = tmessageQueue;
   messageReceiver = tmessageReceiver;
@@ -70,8 +70,10 @@ int PlayerLiveTV::init()
   if (!demuxer) return 0;
   subtitles = new DVBSubtitles(osdReceiver);
   if (!subtitles) return 0;
+
+  teletext = new TeletextDecoderVBIEBU();
  
-  if (!demuxer->init(this, audio, video, 2097152, 524288, subtitles))
+  if (!demuxer->init(this, audio, video, teletext, 2097152, 524288, 65536))
   {
     logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
     shutdown();
@@ -80,6 +82,7 @@ int PlayerLiveTV::init()
 
   vfeed.init();
   afeed.init();
+  tfeed.init();
 
   video->stop();
   video->blank();
@@ -97,7 +100,8 @@ int PlayerLiveTV::shutdown()
 
   delete demuxer;
   delete subtitles;
-
+  delete teletext;
+  teletext = NULL;
   return 1;
 }
 
@@ -121,6 +125,20 @@ void PlayerLiveTV::setAudioChannel(int newChannel, int type)
   return demuxer->setAID(newChannel,type);
 }
 
+void PlayerLiveTV::setSubtitleChannel(int newChannel)
+{
+  return demuxer->setSubID(newChannel);
+}
+
+int *PlayerLiveTV::getTeletxtSubtitlePages()
+{
+    return teletext->getSubtitlePages();
+}
+
+int PlayerLiveTV::getCurrentSubtitleChannel(){
+    return demuxer->getSubID();
+}
+
 bool PlayerLiveTV::toggleSubtitles()
 {
   if (!subtitlesShowing)
@@ -136,6 +154,20 @@ bool PlayerLiveTV::toggleSubtitles()
   return subtitlesShowing;
 }
 
+
+void  PlayerLiveTV::turnSubtitlesOn(bool ison) {
+ if (ison)
+  {
+    subtitlesShowing = true;
+    subtitles->show();
+  }
+  else
+  {
+    subtitlesShowing = false;
+    subtitles->hide();
+  }
+
+}
 // ----------------------------------- Externally called events
 
 void PlayerLiveTV::go(ULONG index)
@@ -322,6 +354,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           afeed.start();
           vfeed.start();
           subtitles->start();
+          tfeed.start();
           
           state = newState;
           return;
@@ -353,6 +386,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           vfeed.stop();
           afeed.stop();
           subtitles->stop();
+          tfeed.stop();
                            
           video->blank();
           video->reset();
@@ -373,8 +407,8 @@ void PlayerLiveTV::switchState(UCHAR newState)
 
           afeed.start();
           vfeed.start();
-          subtitles->start();
-          
+          subtitles->start();     
+          tfeed.start();
           state = newState;
           return;
         }        
@@ -384,9 +418,9 @@ void PlayerLiveTV::switchState(UCHAR newState)
           clearStreamChunks();
           vfeed.stop();
           afeed.stop();
-          subtitles->stop();
-          video->stop();
-          video->blank();
+subtitles->stop();        
+ tfeed.stop();         
video->stop();          video->blank();
           audio->stop();
           audio->reset();
           video->reset();
@@ -420,6 +454,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           vfeed.stop();
           afeed.stop();
           subtitles->stop();
+          tfeed.stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -442,6 +477,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           afeed.start();
           vfeed.start();
           subtitles->start();
+          tfeed.start();
 
           state = newState;
           return;
@@ -453,6 +489,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           vfeed.stop();
           afeed.stop();
           subtitles->stop();
+          tfeed.stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -481,6 +518,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           vfeed.stop();
           afeed.stop();
           subtitles->stop();
+          tfeed.stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -496,6 +534,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           vfeed.stop();
           afeed.stop();
           subtitles->stop();
+          tfeed.stop();
           video->stop();
           video->blank();
           audio->stop();
@@ -518,6 +557,7 @@ void PlayerLiveTV::switchState(UCHAR newState)
           afeed.start();
           vfeed.start();
           subtitles->start();
+          tfeed.start();
 
           state = newState;
           return;
@@ -614,7 +654,8 @@ void PlayerLiveTV::threadMethod()
           }
           if (chan->numSPids > 0)
             demuxer->setSubID(chan->spids[0].pid);
-
+          demuxer->setTID(chan->tpid);
+          teletext->ResetDecoder();
           int streamSuccess = vdr->streamChannel(chan->number, this);
           if (!checkError() && !streamSuccess)
           {      
index eb589c7d0b150515e62594fde785c9fa81b88ff8..ebc3a460cc3e34716ff7d6a01972a2c62a33dea4 100644 (file)
 #include "defines.h"
 #include "vfeed.h"
 #include "afeed.h"
+#include "tfeed.h"
 #include "vdr.h"
 
+#include "teletextdecodervbiebu.h"
+
 class MessageQueue;
 class Audio;
 class Video;
@@ -65,11 +68,18 @@ 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 void setSubtitleChannel(int newChannel);
     virtual bool toggleSubtitles();
+    virtual void turnSubtitlesOn(bool ison); 
+    virtual bool isSubtitlesOn() {return subtitlesShowing;};
 
     virtual bool* getDemuxerMpegAudioChannels();
     virtual bool* getDemuxerAc3AudioChannels();
     virtual int getCurrentAudioChannel();
+    virtual int getCurrentSubtitleChannel();
+    virtual int *getTeletxtSubtitlePages();
+
+    TeletextDecoderVBIEBU * getTeletextDecoder(){return teletext;};
 
     void call(void*); // for callback interface
 
@@ -100,9 +110,11 @@ class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, pub
     Video* video;
     DemuxerTS* demuxer;
     DVBSubtitles* subtitles;
+    TeletextDecoderVBIEBU *teletext;
     VDR* vdr;
     VFeed vfeed;
     AFeed afeed;
+    TFeed tfeed;
     ChannelList* chanList;
 
     queue<PLInstruction> instructions;
index 14209d39a7abf4bf1f43b563eb0cbb40d084bb8d..536ed4c4d3639e477b3de0dd808033b47c35394f 100644 (file)
@@ -57,7 +57,7 @@ PlayerMedia::PlayerMedia(Boxx *parent) : afeed(this), vfeed(this)
        sequence=0;
        demuxer=new DemuxerMedia();
   logger->log("PlayerMedia", Log::DEBUG, "ctorII");
-       if (!demuxer->init(this, audio, video, 2097152, 524288))
+       if (!demuxer->init(this, audio, video, NULL, 2097152, 524288, 0))
   {
     logger->log("PlayerMedia", Log::ERR, "Demuxer failed to init");
     shutdown();
@@ -703,7 +703,7 @@ void PlayerMedia::call(void* caller)
 
 void PlayerMedia::setAudioChannel(int newChannel)
 {
-  demuxer->setAudioChannel(newChannel);
+  demuxer->setAudioStream(newChannel);
 }
 
 bool* PlayerMedia::getDemuxerMpegAudioChannels()
@@ -760,7 +760,7 @@ char * PlayerMedia::getInfo() {
   else {
     sprintf(brbuf,"CBR, %d kBit/s",br*4/10);
   }
-  snprintf(ibuf,500,"%s: %dx%d\n"
+  SNPRINTF(ibuf,500,"%s: %dx%d\n"
                     "%s: %s\n"
                     "%s: %s\n",
                     tr("Format"),
index a16ff23c3edfd4c9e98379f09bfcc2616dde7002..ddd15ba56b29d14b13827664d4725f204b0c5e59 100644 (file)
@@ -74,7 +74,7 @@ int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets)
   demuxer = new DemuxerVDR();
   if (!demuxer) return 0;
 
-  if (!demuxer->init(this, audio, NULL, 0, 40000))
+  if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))
   {
     logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
     shutdown();
index 75baa7a609cee14dd5f022134102c56bc1b445a9..92720f4c0b5b40af943954911d60855d4faf2d8a 100644 (file)
 
 #include "serialize.h"
 #include <stdlib.h>
+#ifndef WIN32
 #include <arpa/inet.h>
+#else
+#include <winsock2.h>
+#endif
+
+
 #ifndef SNPRINTF
 #define SNPRINTF snprintf
 #endif
index caa3aa525bd3698cb6f3982bbf10f53c728f8801..f053f0218bcc238cd8084f877b540058487af21e 100644 (file)
--- a/stream.cc
+++ b/stream.cc
@@ -76,11 +76,12 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type)
   newPacket.length = len;
   newPacket.pos_buffer = 0;
   newPacket.type = type;
-#ifdef WIN32
+  newPacket.pts=0;
   newPacket.synched=false;
+#ifdef WIN32
   newPacket.disconti=false;
-  newPacket.pts=0;
   newPacket.presentation_time=0;
+#endif
   if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES
     //Extract the pts...
     if ((inbuf[7] & 0x80) && len>14 ) {
@@ -90,12 +91,13 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type)
                     ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
                      ( (ULLONG)(inbuf[12])        <<  7 ) |
                      ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
+#ifdef WIN32
         //ok we have the pts now convert it to a continously time code in 100ns units
         newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
         newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti);
+#endif
     }
   }
-#endif
 
   lock();
   int front, back;
index 70f3024b5e649364cb5b21a593715d5e4ec8115a..13a1daa70b367056fd3e776e19a67b85431f657e 100644 (file)
@@ -55,6 +55,7 @@ int Surface::drawText(const char* text, int x, int y, int width, ULONG rgba)
 
   X = 0;
   cx = 0;
+  startFastDraw();
   for (i=0; i<n; i++)
   {
     unsigned char c = text[i];
@@ -68,13 +69,14 @@ int Surface::drawText(const char* text, int x, int y, int width, ULONG rgba)
       {
         if ((character[Y] >> (32 - X)) & 0x1)
         {
-          drawPixel(x+X+cx, y+Y, rgba);
+          drawPixel(x+X+cx, y+Y, rgba,true);
           pixels++;
         }
       }
     }
     cx += w;
   }
+  endFastDraw();
   return 1;
 }
 
index 628b6219b1fb8c6b29200fed86b6a57a17df5325..ce412ac4da4829858fb8b5ace8d5faceac6ced47 100644 (file)
--- a/surface.h
+++ b/surface.h
@@ -61,9 +61,8 @@ class Surface
     virtual void display()=0;
 
     virtual int fillblt(int x, int y, int width, int height, unsigned int c)=0;
-    virtual void drawPixel(int x, int y, unsigned int c)=0;
-    virtual void drawPixel(int x, int y, Colour& c)=0;
-    virtual void drawHorzLine(int x1, int x2, int y, unsigned int c)=0;
+    virtual void drawPixel(int x, int y, unsigned int c, bool fastdraw=false)=0;
+    virtual void drawPixel(int x, int y, Colour& c, bool fastdraw=false)=0;    virtual void drawHorzLine(int x1, int x2, int y, unsigned int c)=0;
     virtual void drawVertLine(int x, int y1, int y2, unsigned int c)=0;
     virtual void drawBitmap(int x, int y, const Bitmap& bm)=0;
     virtual int updateToScreen(int sx, int sy, int w, int h, int dx, int dy)=0;
index 7280453eb95eaf5a4b6a25a85d199c751efe35c9..5fd5b59d3920fd05d9f98e8052af04de90217caf 100644 (file)
@@ -200,7 +200,7 @@ int SurfaceMVP::fillblt(int x, int y, int width, int height, unsigned int c)
   return ioctl(fdOsd, GFX_FB_OSD_FILLBLT, &fblt);
 }
 
-void SurfaceMVP::drawPixel(int x, int y, unsigned int c)
+void SurfaceMVP::drawPixel(int x, int y, unsigned int c, bool fastdraw)
 {
   int offset;
   unsigned char r, g, b, a, Y, U, V;
@@ -225,9 +225,9 @@ void SurfaceMVP::drawPixel(int x, int y, unsigned int c)
   *(surface.base[1] + (offset & 0xfffffffe)) = U;
   *(surface.base[1] + (offset & 0xfffffffe) + 1) = V;
   *(surface.base[2] + offset) = a;
-
 }
-void SurfaceMVP::drawPixel(int x, int y, Colour& c)
+
+void SurfaceMVP::drawPixel(int x, int y, Colour& c, bool fastdraw)
 {
   int offset;
   unsigned char Y, U, V;
@@ -251,9 +251,7 @@ void SurfaceMVP::drawPixel(int x, int y, Colour& c)
   *(surface.base[1] + (offset & 0xfffffffe)) = U;
   *(surface.base[1] + (offset & 0xfffffffe) + 1) = V;
   *(surface.base[2] + offset) = 0xff;
-
 }
-
  
 void SurfaceMVP::drawHorzLine(int x1, int x2, int y, unsigned int c)
 {
index 752a24a26e1e4209c15d6fec0cbee59e02c8e0f9..91598b53843da4cc1044c0ba1c55736107e68875 100644 (file)
@@ -161,8 +161,8 @@ class SurfaceMVP : public Surface
     unsigned long getSurfaceHandle();
 
     int fillblt(int x, int y, int width, int height, unsigned int rgba);
-    void drawPixel(int x, int y, unsigned int c);
-    void drawPixel(int x, int y, Colour& c);    
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
     void drawHorzLine(int x1, int x2, int y, unsigned int c);
     void drawVertLine(int x, int y1, int y2, unsigned int c);
     void drawBitmap(int x, int y, const Bitmap& bm);
index 106a3c36b1ad602a41fa12c0461f675dde42485b..5153c387b89095c91a46ee074e6a79f1670dfda6 100644 (file)
@@ -29,7 +29,7 @@ SurfaceWin::SurfaceWin(int id)
   d3dtexture=NULL;
   d3dsurface=NULL;
   sheight=swidth=0;
-  fastdraw=false;
+//  fastdraw=false;
   event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
 }
 
@@ -151,7 +151,7 @@ void SurfaceWin::startFastDraw(){
       return ;
     }
   }
-  fastdraw=true;
+//  fastdraw=true;
 }
 void SurfaceWin::endFastDraw(){
     OsdWin* osd=((OsdWin*)(Osd::getInstance()));
@@ -160,19 +160,19 @@ void SurfaceWin::endFastDraw(){
       return ;
     }
     osd->EndPainting();
-    fastdraw=false;
+//    fastdraw=false;
  }
 
-void SurfaceWin::drawPixel(int x, int y, Colour & colour) {
+void SurfaceWin::drawPixel(int x, int y, Colour & colour, bool fastdraw) {
   int c = (  (0xFF000000         )
              | (colour.red    << 16)
              | (colour.green  <<  8)
              | (colour.blue        ) );
 
-    drawPixel(x, y, c);
+    drawPixel(x, y, c, fastdraw);
   }
 
-void SurfaceWin::drawPixel(int x, int y, unsigned int c)
+void SurfaceWin::drawPixel(int x, int y, unsigned int c, bool fastdraw)
 {
   //FixMe: locking for every single Pixel will be painfully slow
     OsdWin* osd;
@@ -230,7 +230,7 @@ void SurfaceWin::drawBitmap(int x, int y, const Bitmap& bm)
   startFastDraw();
   for (UINT j = 0; j < bm.getHeight(); ++j)
     for (UINT i = 0; i < bm.getWidth(); ++i)
-      drawPixel(x+i, y+j, bm.getColour(i,j));
+      drawPixel(x+i, y+j, bm.getColour(i,j),true);
   endFastDraw();
 }
 
index 0004ac70da5f53ec8c32b65e020c5b1e81319288..8d9cd9dfe63cc051098cc27b79a3857efb8c1edd 100644 (file)
@@ -39,8 +39,8 @@ class SurfaceWin : public Surface
     void endFastDraw();
 
     int fillblt(int x, int y, int width, int height, unsigned int c);
-    void drawPixel(int x, int y, unsigned int c);
-    void drawPixel(int x, int y, Colour& c);
+    void drawPixel(int x, int y, Colour& c, bool fastdraw=false);
+    void drawPixel(int x, int y, unsigned int c, bool fastdraw=false);
     void drawHorzLine(int x1, int x2, int y, unsigned int c);
     void drawVertLine(int x, int y1, int y2, unsigned int c);
     void drawBitmap(int x, int y, const Bitmap& bm);
@@ -60,7 +60,6 @@ class SurfaceWin : public Surface
     D3DLOCKED_RECT lockrect;
     UINT sheight,swidth;
     HANDLE event;
-    bool fastdraw;
 };
 
 #endif
diff --git a/teletextdecodervbiebu.cc b/teletextdecodervbiebu.cc
new file mode 100644 (file)
index 0000000..44e2c16
--- /dev/null
@@ -0,0 +1,834 @@
+/*\r
+    Copyright 2008 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+\r
+/* Portions from vdr osdteletext plugin "txtrender.c": */\r
+/***************************************************************************\r
+ *                                                                         *\r
+ *   txtrender.c - Teletext display abstraction and teletext code          *\r
+ *                 renderer                                                *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   Changelog:                                                            *\r
+ *     2005-03    initial version (c) Udo Richter                          *\r
+ *                                                                         *\r
+ ***************************************************************************/\r
+\r
+#include "teletextdecodervbiebu.h"\r
+#include "teletxt/tables.h"\r
+#include "message.h"\r
+#include "command.h"\r
+#include "video.h"\r
+\r
+#ifdef WIN32\r
+#include <windows.h>\r
+#endif\r
+\r
+TeletextDecoderVBIEBU::TeletextDecoderVBIEBU()\r
+{\r
+    selectedpage=0x100;\r
+    ourpage=false;\r
+    flags=lang=0; \r
+  \r
+    CleanPage();\r
+    FirstG0CodePage=0;\r
+    SecondG0CodePage=0;\r
+    dirty=false;\r
+    txtview=NULL;\r
+    firstlineupdate=0;\r
+    gotcha=false;\r
+    char digits[]={'1','0','0'};\r
+    setKeyinDigits(digits,false);\r
+    isrecording=false;\r
+    for (int i=0;i<10;i++) record_pages[i]=-1;\r
+    \r
+\r
+}\r
+\r
+TeletextDecoderVBIEBU::~TeletextDecoderVBIEBU()\r
+{\r
+\r
+\r
+}\r
+\r
+long long TeletextDecoderVBIEBU::SetStartOffset(long long curreftime, bool *rsync)\r
+{\r
+  return 0;  \r
+}\r
+\r
+void TeletextDecoderVBIEBU::ResetTimeOffsets()\r
+{\r
+\r
+}\r
+\r
+\r
+\r
+void TeletextDecoderVBIEBU::ResetDecoder()\r
+{\r
+    gotcha=false;\r
+    ourpage=false;\r
+    firstlineupdate=0;\r
+    selectedpage=0x100;\r
+    CleanPage();\r
+    char digits[]={'1','0','0'};\r
+    setKeyinDigits(digits,false);\r
+    for (int i=0;i<10;i++) record_pages[i]=-1;\r
+  \r
+}\r
+\r
+void TeletextDecoderVBIEBU::setPage(unsigned int newpage)\r
+{\r
+    selectedpage=newpage;\r
+    gotcha=false;\r
+    ourpage=false;\r
+    firstlineupdate=0;\r
+    for (int i=0;i<25;i++) {\r
+        memset(curpage[i],0,40);\r
+    }\r
+}\r
+\r
+void TeletextDecoderVBIEBU::CleanPage()\r
+{\r
+    int x,y;\r
+    for (int i=0;i<25;i++) {\r
+        memset(curpage[i],0,40);\r
+    }\r
+    for (y=0;y<25;y++) {\r
+        for (x=0;x<40;x++) {\r
+            cTeletextChar c;\r
+            c.SetFGColor(ttcWhite);\r
+            c.SetBGColor(ttcBlack);\r
+            c.SetCharset(CHARSET_LATIN_G0);\r
+            c.SetChar(' ');\r
+            if (flags&0x60) {\r
+                c.SetBoxedOut(true);    \r
+            }\r
+            setChar(x,y,c);\r
+        }\r
+    } \r
+\r
+}\r
+void TeletextDecoderVBIEBU::setKeyinDigits(char digits[3],bool inKeying)\r
+{\r
+    int x;\r
+    inkeying=inKeying;\r
+    for (x=0;x<3;x++) {\r
+        cTeletextChar c;\r
+        c.SetFGColor(ttcWhite);\r
+        c.SetBGColor(ttcBlack);\r
+        c.SetCharset(CHARSET_LATIN_G0);\r
+        c.SetChar(digits[x]);\r
+        if (flags&0x60) {\r
+            c.SetBoxedOut(true);    \r
+        }\r
+        setChar(x+3,0,c);\r
+        keyindigits[x]=digits[x];\r
+    }\r
+}\r
+\r
+void TeletextDecoderVBIEBU::PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos)\r
+{\r
+    mediapacket = mplist.front();\r
+}\r
+\r
+static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
+{\r
+  // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
+  if (pts1 > pts2)\r
+    return pts1 - pts2;\r
+  else\r
+    return (1LL<<33) + pts1 - pts2;\r
+}\r
+\r
+UINT TeletextDecoderVBIEBU::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)\r
+{\r
+   if (mediapacket.type != MPTYPE_TELETEXT)\r
+   {\r
+       *samplepos= 0;\r
+       return 1; //Skip it! \r
+   }\r
+   unsigned int headerstrip;\r
+   unsigned char txtdata[43];\r
+   headerstrip=buffer[mediapacket.pos_buffer+8]+9;\r
+   //headerstrip+=4; //substream id\r
+   unsigned int datapos=0;\r
+   unsigned int datatype=buffer[mediapacket.pos_buffer+headerstrip+0];\r
+   //Chris should we use here the pts data from mediapacket ?\r
+   // in this case the data fields should also be added in mediamvp\r
+   if (mediapacket.synched)\r
+    { // An entry exists in the work list\r
+        ULLONG nowPTS = Video::getInstance()->getCurrentTimestamp();\r
+       if (PTSDifference(mediapacket.pts, nowPTS) >= 1200*90000) {\r
+            *samplepos=0;\r
+            return 1;//bad data skip it\r
+        }\r
+        if (nowPTS < (mediapacket.pts-4000)  ) {\r
+            *samplepos=0;\r
+            return 0;\r
+        } \r
+   }\r
+   \r
+   if (( datatype>=0x10 && datatype <=0x1F) ||\r
+       ( datatype>=0x99 && datatype <=0x9B)) {\r
+       //EBU VBI DATA\r
+       datapos++;\r
+       while (datapos< (mediapacket.length-headerstrip)) {\r
+           unsigned int unit_id=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+           datapos++;\r
+           unsigned int unit_length=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+           datapos++;\r
+           switch (unit_id) {\r
+               case 0x02:\r
+               case 0x03: {//Teletext with and without subtitles\r
+                   //call teletext decoder\r
+                   unsigned int field=buffer[mediapacket.pos_buffer+headerstrip+datapos];\r
+\r
+                   if ((datapos+44)< (mediapacket.length-headerstrip)) {\r
+                       for (int i=0;i<42;i++) {\r
+                           txtdata[i]=invtab[buffer[mediapacket.pos_buffer+headerstrip+datapos+2+i]];\r
+                       }\r
+                       DecodeTeletext(txtdata,field);\r
+                   }\r
+                          }break;\r
+               case  0xC0: //inverted Teletext\r
+                   //call teletext decoder\r
+               break;\r
+               \r
+               case 0xC3: //VPS\r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               case 0xC4: //WSS\r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               case 0xC5: //CC\r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               case 0xC6: //monochrome 4:2:2 samples, what is that? \r
+                   //what to do with this, in the moment we do not need it\r
+               break;\r
+               default:\r
+               // case 0x00,0x01,0x04..0x7f,0x80..0xbf,0xc1,0xc2,0xc7..0xfe,0xff: //discard\r
+                   //discard\r
+               break;\r
+           };\r
+           datapos+=unit_length;\r
+       //    while (buffer[mediapacket.pos_buffer+headerstrip+datapos]==0xFF &&(datapos< (mediapacket.length-headerstrip))) {\r
+        //       datapos++; //stuffing bytes\r
+         //  }\r
+\r
+           \r
+       }\r
+       *samplepos=0;\r
+       return 1;\r
+\r
+\r
+   } else {\r
+           *samplepos= 0;\r
+           return 1; //Skip it! and discard data   \r
+   }\r
+\r
+   return 0;\r
+\r
+}\r
+// This part is inspired by the vdr-plugin-osdteletext of Udo Richter and Marcel Wiesweg\r
+void TeletextDecoderVBIEBU::DecodeTeletext(const UCHAR* buffer, unsigned int field) //needs to be exactly 42 byte long!!\r
+{\r
+   UCHAR hdrbuf[5];\r
+   for (int i=0;i<5;i++) hdrbuf[i]=(unhamtab[buffer[2*i]]&0xF) | ((unhamtab[buffer[2*i+1]]&0xF)<< 4);\r
+   int header=hdrbuf[0];\r
+   int magazin=header & 0x7;\r
+   int line = (header>>3) & 0x1f;\r
+   if (magazin==0) magazin=8;\r
+   if (line==0)\r
+   {\r
+       if (ourpage) {\r
+           gotcha=true;\r
+           inkeying=false;\r
+           RenderTeletextCode(false);\r
+       } else {\r
+           RenderTeletextCode(true);\r
+       }\r
+       int pagenumber=hdrbuf[1];\r
+       int pagemagazin=magazin<<8 | pagenumber;\r
+       int pagesubnumber=(hdrbuf[2]) || ((hdrbuf[3]<<8) & 0x3f7f);\r
+\r
+       if (pagemagazin == selectedpage) ourpage=true;\r
+       else ourpage=false;\r
+       if (isrecording) {\r
+           for (int i=0;i<10;i++) {\r
+               if (pagemagazin==record_pages[i]) break;\r
+               if (record_pages[i]==-1) {\r
+                   record_pages[i]=pagemagazin;\r
+                   break;\r
+               }\r
+           }\r
+       }\r
+       if (hdrbuf[3] &0x80) { //This is a subtitle\r
+            for (int i=0;i<10;i++) {\r
+               if (pagemagazin==record_pages[i]) break;\r
+               if (record_pages[i]==-1) {\r
+                   record_pages[i]=pagemagazin;\r
+                   break;\r
+               }\r
+           }\r
+       }\r
+\r
+\r
+       if (ourpage) {\r
+           lang=((hdrbuf[4]>>5) & 0x07);\r
+           flags=hdrbuf[2] & 0x80;\r
+           flags|=(hdrbuf[3]&0x40)|((hdrbuf[3]>>2)&0x20); //??????\r
+           flags|=((hdrbuf[4]<<4)&0x10)|((hdrbuf[4]<<2)&0x08)|(hdrbuf[4]&0x04)|((hdrbuf[4]>>1)&0x02)|((hdrbuf[4]>>4)&0x01);\r
+           for (int i=0;i<25;i++) {\r
+               memset(curpage[i],0,40);\r
+            }\r
+       }\r
+       \r
+       memcpy(curpage[line],buffer+2,40);\r
+   } else if (ourpage && (line<=25)) {\r
+       memcpy(curpage[line],buffer+2,40);\r
+       \r
+   }\r
+}\r
+\r
+\r
+/* from osdteletext plugin: (slightly adapted for vomp)*/\r
+// Font tables\r
+\r
+// teletext uses 7-bit numbers to identify a font set.\r
+// There are three font sets involved:\r
+// Primary G0, Secondary G0, and G2 font set.\r
+\r
+// Font tables are organized in blocks of 8 fonts:\r
+\r
+enumCharsets FontBlockG0_0000[8] = {\r
+    CHARSET_LATIN_G0_EN,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_SV_FI,\r
+    CHARSET_LATIN_G0_IT,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_LATIN_G0_PT_ES,\r
+    CHARSET_LATIN_G0_CZ_SK,\r
+    CHARSET_LATIN_G0\r
+};\r
+\r
+enumCharsets FontBlockG2Latin[8]={\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_0001[8] = {\r
+    CHARSET_LATIN_G0_PL,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_SV_FI,\r
+    CHARSET_LATIN_G0_IT,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0_CZ_SK,\r
+    CHARSET_LATIN_G0\r
+};\r
+\r
+enumCharsets FontBlockG0_0010[8] = {\r
+    CHARSET_LATIN_G0_EN,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_SV_FI,\r
+    CHARSET_LATIN_G0_IT,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_LATIN_G0_PT_ES,\r
+    CHARSET_LATIN_G0_TR,\r
+    CHARSET_LATIN_G0\r
+};\r
+\r
+\r
+enumCharsets FontBlockG0_0011[8] = {\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0_SR_HR_SL,\r
+    CHARSET_LATIN_G0,\r
+    CHARSET_LATIN_G0_RO\r
+};\r
+\r
+enumCharsets FontBlockG0_0100[8] = {\r
+    CHARSET_CYRILLIC_G0_SR_HR,\r
+    CHARSET_LATIN_G0_DE,\r
+    CHARSET_LATIN_G0_EE,\r
+    CHARSET_LATIN_G0_LV_LT,\r
+    CHARSET_CYRILLIC_G0_RU_BG,\r
+    CHARSET_CYRILLIC_G0_UK,\r
+    CHARSET_LATIN_G0_CZ_SK,\r
+    CHARSET_INVALID\r
+};\r
+\r
+enumCharsets FontBlockG2_0100[8] = {\r
+    CHARSET_CYRILLIC_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_CYRILLIC_G2,\r
+    CHARSET_CYRILLIC_G2,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_INVALID\r
+};\r
+\r
+enumCharsets FontBlockG0_0110[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_LATIN_G0_TR,\r
+    CHARSET_GREEK_G0\r
+};\r
+\r
+enumCharsets FontBlockG2_0110[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_LATIN_G2,\r
+    CHARSET_GREEK_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_1000[8] = {\r
+    CHARSET_LATIN_G0_EN,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_LATIN_G0_FR,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G0\r
+};\r
+\r
+enumCharsets FontBlockG2_1000[8] = {\r
+    CHARSET_ARABIC_G2,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2\r
+};\r
+\r
+enumCharsets FontBlockG0_1010[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_HEBREW_G0,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G0,\r
+};\r
+\r
+enumCharsets FontBlockG2_1010[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2,\r
+    CHARSET_INVALID,\r
+    CHARSET_ARABIC_G2,\r
+};\r
+\r
+enumCharsets FontBlockInvalid[8] = {\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID,\r
+    CHARSET_INVALID\r
+};\r
+\r
+\r
+\r
+// The actual font table definition:\r
+// Split the 7-bit number into upper 4 and lower 3 bits,\r
+// use upper 4 bits for outer array,\r
+// use lower 3 bits for inner array\r
+\r
+struct structFontBlock {\r
+    enumCharsets *G0Block;\r
+    enumCharsets *G2Block;\r
+};\r
+    \r
+structFontBlock FontTable[16] = {\r
+    { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block\r
+    { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block\r
+    { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block\r
+    { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block\r
+    { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 0101 block\r
+    { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 0111 block\r
+    { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1001 block\r
+    { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1011 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1100 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1101 block\r
+    { FontBlockInvalid, FontBlockInvalid }, // 1110 block\r
+    { FontBlockInvalid, FontBlockInvalid }  // 1111 block\r
+};\r
+\r
+inline enumCharsets GetG0Charset(int codepage) {\r
+    return FontTable[codepage>>3].G0Block[codepage&7];\r
+}\r
+inline enumCharsets GetG2Charset(int codepage) {\r
+    return FontTable[codepage>>3].G2Block[codepage&7];\r
+}\r
+\r
+enum enumSizeMode {\r
+    // Possible size modifications of characters\r
+    sizeNormal,\r
+    sizeDoubleWidth,\r
+    sizeDoubleHeight,\r
+    sizeDoubleSize\r
+};\r
+\r
+void TeletextDecoderVBIEBU::RenderTeletextCode(bool renderfirstlineonly) {\r
+    int x,y;\r
+    bool EmptyNextLine=false;\r
+    // Skip one line, in case double height chars were/will be used\r
+\r
+    // Get code pages:\r
+    int LocalG0CodePage=(FirstG0CodePage & 0x78) \r
+            | ((lang & 0x04)>>2) | (lang & 0x02) | ((lang & 0x01)<<2);\r
+    enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);\r
+    enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);\r
+    // Reserved for later use:\r
+    // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);\r
+    \r
+    for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {\r
+        // Start of line: Set start of line defaults\r
+        \r
+        // Hold Mosaics mode: Remember last mosaic char/charset \r
+        // for next spacing code\r
+        bool HoldMosaics=false;\r
+        unsigned char HoldMosaicChar=' ';\r
+        enumCharsets HoldMosaicCharset=FirstG0;\r
+\r
+        enumSizeMode Size=sizeNormal;\r
+        // Font size modification\r
+        bool SecondCharset=false;\r
+        // Use primary or secondary G0 charset\r
+        bool GraphicCharset=false;\r
+        // Graphics charset used?\r
+        bool SeparateGraphics=false;\r
+        // Use separated vs. contiguous graphics charset\r
+        bool NoNextChar=false;\r
+        // Skip display of next char, for double-width\r
+        EmptyNextLine=false;\r
+        // Skip next line, for double-height\r
+\r
+        cTeletextChar c;\r
+        // auto.initialized to everything off\r
+        c.SetFGColor(ttcWhite);\r
+        c.SetBGColor(ttcBlack);\r
+        c.SetCharset(FirstG0);\r
+        \r
+        if (y==0 && (flags&0x10)) {\r
+            if (!inkeying ) c.SetBoxedOut(true);\r
+            \r
+        }\r
+        if (flags&0x60) {\r
+           if (!(inkeying && y==0) ) c.SetBoxedOut(true);\r
+            \r
+        }\r
+        if (y==0) {\r
+            \r
+            for (x=0;x<8;x++) {\r
+                cTeletextChar c2=c;\r
+               \r
+                if (x>=3 && x<6){\r
+                    c2.SetChar(keyindigits[x-3]);\r
+\r
+                }\r
+                else\r
+                    c2.SetChar(' ');\r
+                setChar(x,0,c2);\r
+            }\r
+        }\r
+\r
+        // Pre-scan for double-height and double-size codes\r
+        for (x=0;x<40;x++) {\r
+            if (y==0 && x<8) x=8;\r
+            if ((curpage[y][x] & 0x7f)==0x0D || (curpage[y][x] & 0x7f)==0x0F)\r
+                EmptyNextLine=true;\r
+        }\r
+\r
+        // Move through line\r
+        for (x=0;x<40;x++) {\r
+            unsigned char ttc=curpage[y][x] & 0x7f;\r
+            // skip parity check\r
+\r
+            if (y==0 && x<8) continue;\r
+            if (y==0 && x<31 && renderfirstlineonly && gotcha && !inkeying) continue;\r
+            // no displayable data here...\r
+            \r
+/*          // Debug only: Output line data and spacing codes\r
+            if (y==6) {\r
+                if (ttc<0x20)\r
+                    printf("%s ",names[ttc]);\r
+                else\r
+                    printf("%02x ",ttc);\r
+                if (x==39) printf("\n");\r
+            }\r
+*/          \r
+            \r
+            // Handle all 'Set-At' spacing codes\r
+            switch (ttc) {\r
+            case 0x09: // Steady\r
+                c.SetBlink(false);\r
+                break;\r
+            case 0x0C: // Normal Size\r
+                if (Size!=sizeNormal) {\r
+                    Size=sizeNormal;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+                break;\r
+            case 0x18: // Conceal\r
+                c.SetConceal(true);\r
+                break;\r
+            case 0x19: // Contiguous Mosaic Graphics\r
+                SeparateGraphics=false;\r
+                if (GraphicCharset)\r
+                    c.SetCharset(CHARSET_GRAPHICS_G1);\r
+                break;\r
+            case 0x1A: // Separated Mosaic Graphics\r
+                SeparateGraphics=true;\r
+                if (GraphicCharset)\r
+                    c.SetCharset(CHARSET_GRAPHICS_G1_SEP);\r
+                break;\r
+            case 0x1C: // Black Background\r
+                c.SetBGColor(ttcBlack);\r
+                break;\r
+            case 0x1D: // New Background\r
+                c.SetBGColor(c.GetFGColor());\r
+                break;\r
+            case 0x1E: // Hold Mosaic\r
+                HoldMosaics=true;               \r
+                break;\r
+            }\r
+\r
+            // temporary copy of character data:\r
+            cTeletextChar c2=c;\r
+            // c2 will be text character or space character or hold mosaic\r
+            // c2 may also have temporary flags or charsets\r
+            \r
+            if (ttc<0x20) {\r
+                // Spacing code, display space or hold mosaic\r
+                if (HoldMosaics) {\r
+                    c2.SetChar(HoldMosaicChar);\r
+                    c2.SetCharset(HoldMosaicCharset);\r
+                } else {\r
+                    c2.SetChar(' ');\r
+                }\r
+            } else {\r
+                // Character code               \r
+                c2.SetChar(ttc);\r
+                if (GraphicCharset) {\r
+                    if (ttc&0x20) {\r
+                        // real graphics code, remember for HoldMosaics\r
+                        HoldMosaicChar=ttc;\r
+                        HoldMosaicCharset=c.GetCharset();\r
+                    } else {\r
+                        // invalid code, pass-through to G0\r
+                        c2.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+                    }   \r
+                }\r
+            }\r
+            \r
+            // Handle double-height and double-width extremes\r
+            if (y>=23) {\r
+                if (Size==sizeDoubleHeight) Size=sizeNormal;\r
+                if (Size==sizeDoubleSize) Size=sizeDoubleWidth;\r
+            }\r
+            if (x>=38) {\r
+                if (Size==sizeDoubleWidth) Size=sizeNormal;\r
+                if (Size==sizeDoubleSize) Size=sizeDoubleHeight;\r
+            }\r
+            \r
+            // Now set character code\r
+            \r
+            if (NoNextChar) {\r
+                // Suppress this char due to double width last char\r
+                NoNextChar=false;\r
+            } else {\r
+                switch (Size) {\r
+                case sizeNormal:\r
+                    // Normal sized\r
+                    setChar(x,y,c2);\r
+                    if (EmptyNextLine && y<23) {\r
+                        // Clean up next line\r
+                        setChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+                    }\r
+                    break;\r
+                case sizeDoubleWidth:\r
+                    // Double width\r
+                    setChar(x,y,c2.ToDblWidth(dblw_Left));\r
+                    setChar(x+1,y,c2.ToDblWidth(dblw_Right));\r
+                    if (EmptyNextLine && y<23) {\r
+                        // Clean up next line\r
+                        setChar(x  ,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+                        setChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));\r
+                    }\r
+                    NoNextChar=true;\r
+                    break;\r
+                case sizeDoubleHeight:\r
+                    // Double height\r
+                    setChar(x,y,c2.ToDblHeight(dblh_Top));\r
+                    setChar(x,y+1,c2.ToDblHeight(dblh_Bottom));\r
+                    break;\r
+                case sizeDoubleSize:\r
+                    // Double Size\r
+                    setChar(x  ,  y,c2.ToDblHeight(dblh_Top   ).ToDblWidth(dblw_Left ));\r
+                    setChar(x+1,  y,c2.ToDblHeight(dblh_Top   ).ToDblWidth(dblw_Right));\r
+                    setChar(x  ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));\r
+                    setChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));\r
+                    NoNextChar=true;\r
+                    break;\r
+                }\r
+            }\r
+                \r
+            // Handle all 'Set-After' spacing codes\r
+             if (ttc>=0x00 &&  ttc<=0x07) { // Set FG color\r
+                if (GraphicCharset) {\r
+                    // Actual switch from graphics charset\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }\r
+                c.SetFGColor((enumTeletextColor)ttc);\r
+                c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+                GraphicCharset=false;\r
+                c.SetConceal(false);\r
+             } else if (ttc==0x08) {\r
+                c.SetBlink(true);\r
+             } else if (ttc==0x0A) {\r
+                c.SetBoxedOut(true);\r
+             } else if (ttc==0x0B) {\r
+             // Start Box\r
+                c.SetBoxedOut(false);\r
+             } else if (ttc==0x0D) {\r
+                if (Size!=sizeDoubleHeight) {\r
+                    Size=sizeDoubleHeight;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+             } else if (ttc==0x0E) {\r
+                if (Size!=sizeDoubleWidth) {\r
+                    Size=sizeDoubleWidth;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+             } else if (ttc==0x0E) {\r
+                if (Size!=sizeDoubleSize) {\r
+                    Size=sizeDoubleSize;\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }                   \r
+             } else  if (ttc>=0x10 && ttc<=0x17) { \r
+                if (!GraphicCharset) {\r
+                    // Actual switch to graphics charset\r
+                    HoldMosaicChar=' ';\r
+                    HoldMosaicCharset=FirstG0;\r
+                }\r
+                c.SetFGColor((enumTeletextColor)(ttc-0x10));\r
+                c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);\r
+                GraphicCharset=true;\r
+                c.SetConceal(false);\r
+             } else if (ttc==0x1B) {\r
+                SecondCharset=!SecondCharset;\r
+                if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);\r
+             } else if (ttc==0x1F) {\r
+                HoldMosaics=false;\r
+             }\r
+            \r
+        } // end for x\r
+        if (renderfirstlineonly) break;\r
+    } // end for y\r
+    \r
+    for (x=0;x<40;x++) {\r
+        // Clean out last line\r
+        cTeletextChar c;\r
+        c.SetFGColor(ttcWhite);\r
+        c.SetBGColor(ttcBlack);\r
+        c.SetCharset(FirstG0);\r
+        c.SetChar(' ');\r
+        if (flags&0x60) {\r
+            c.SetBoxedOut(true);    \r
+        }\r
+        setChar(x,24,c);\r
+    } \r
+    for (y=0;y<25;y++) {\r
+        for (x=0;x<40;x++) {\r
+            if (isDirty(x,y)) {\r
+                dirty=true;\r
+                break;\r
+            }\r
+            if (dirty) break;\r
+        }\r
+        if (dirty) break;\r
+    }\r
+     \r
+    if (dirty && txtview!=NULL ) {\r
+        \r
+        if ( !renderfirstlineonly) {\r
+            Message* m= new Message();\r
+            m->message = Message::TELETEXTUPDATE;\r
+            m->to = txtview;\r
+            m->from = this;\r
+            m->parameter = 0;\r
+            Command::getInstance()->postMessageFromOuterSpace(m);\r
+        } else if (firstlineupdate==10) {\r
+            Message* m= new Message();\r
+            m->message = Message::TELETEXTUPDATEFIRSTLINE;\r
+            m->to = txtview;\r
+            m->from = this;\r
+            m->parameter = 0;\r
+            Command::getInstance()->postMessageFromOuterSpace(m);\r
+            firstlineupdate=0;\r
+        } else firstlineupdate++;\r
+        \r
+       \r
+    }\r
+        \r
+}\r
diff --git a/teletextdecodervbiebu.h b/teletextdecodervbiebu.h
new file mode 100644 (file)
index 0000000..0566a40
--- /dev/null
@@ -0,0 +1,330 @@
+/*\r
+    Copyright 2008 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+/* Portions from vdr osdteletext plugin "txtrender.c": */\r
+/***************************************************************************\r
+ *                                                                         *\r
+ *   txtrender.h - Teletext display abstraction and teletext code          *\r
+ *                 renderer                                                *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   Changelog:                                                            *\r
+ *     2005-03    initial version (c) Udo Richter                          *\r
+ *                                                                         *\r
+ ***************************************************************************/\r
+\r
+#ifndef TXTDECVBIEBU_H\r
+#define TXTDECVBIEBU_H\r
+\r
+#include "draintarget.h"\r
+#include "log.h"\r
+\r
+/* from osdteletext begin */\r
+\r
+// Teletext character sets\r
+enum enumCharsets {\r
+    CHARSET_LATIN_G0          = 0x0000, // native latin (partially todo)\r
+    CHARSET_LATIN_G0_CZ_SK    = 0x0100, // Czech/Slovak (todo)\r
+    CHARSET_LATIN_G0_EN       = 0x0200, // English\r
+    CHARSET_LATIN_G0_EE       = 0x0300, // Estonian (todo)\r
+    CHARSET_LATIN_G0_FR       = 0x0400, // French\r
+    CHARSET_LATIN_G0_DE       = 0x0500, // German\r
+    CHARSET_LATIN_G0_IT       = 0x0600, // Italian\r
+    CHARSET_LATIN_G0_LV_LT    = 0x0700, // Lettish/Lithuanian (todo)\r
+    CHARSET_LATIN_G0_PL       = 0x0800, // Polish (todo)\r
+    CHARSET_LATIN_G0_PT_ES    = 0x0900, // Portugese/Spanish\r
+    CHARSET_LATIN_G0_RO       = 0x0A00, // Romanian (todo)\r
+    CHARSET_LATIN_G0_SR_HR_SL = 0x0B00, // Serbian/Croatian/Slovenian (todo)\r
+    CHARSET_LATIN_G0_SV_FI    = 0x0C00, // Swedish/Finnish\r
+    CHARSET_LATIN_G0_TR       = 0x0D00, // Turkish (todo)\r
+    CHARSET_LATIN_G2          = 0x0E00, // Latin G2 supplementary set (todo)\r
+    CHARSET_CYRILLIC_G0_SR_HR = 0x0F00, // Serbian/Croatian (todo)\r
+    CHARSET_CYRILLIC_G0_RU_BG = 0x1000, // Russian/Bulgarian (todo)\r
+    CHARSET_CYRILLIC_G0_UK    = 0x1100, // Ukrainian (todo)\r
+    CHARSET_CYRILLIC_G2       = 0x1200, // Cyrillic G2 Supplementary (todo)\r
+    CHARSET_GREEK_G0          = 0x1300, // Greek G0 (todo)\r
+    CHARSET_GREEK_G2          = 0x1400, // Greeek G2 (todo)\r
+    CHARSET_ARABIC_G0         = 0x1500, // Arabic G0 (todo)\r
+    CHARSET_ARABIC_G2         = 0x1600, // Arabic G2 (todo)\r
+    CHARSET_HEBREW_G0         = 0x1700, // Hebrew G0 (todo)\r
+    CHARSET_GRAPHICS_G1       = 0x1800, // G1 graphics set\r
+    CHARSET_GRAPHICS_G1_SEP   = 0x1900, // G1 graphics set, separated\r
+    CHARSET_GRAPHICS_G3       = 0x1A00, // G3 graphics set (todo)\r
+    CHARSET_INVALID           = 0x1F00  // no charset defined\r
+};\r
+\r
+// Macro to get the lowest non-0 bit position from a bit mask\r
+// Should evaluate to const on a const mask\r
+#define LowestSet2Bit(mask) ((mask)&0x0001?0:1)\r
+#define LowestSet4Bit(mask) ((mask)&0x0003?LowestSet2Bit(mask):LowestSet2Bit((mask)>>2)+2)\r
+#define LowestSet8Bit(mask) ((mask)&0x000f?LowestSet4Bit(mask):LowestSet4Bit((mask)>>4)+4)\r
+#define LowestSet16Bit(mask) ((mask)&0x00ff?LowestSet8Bit(mask):LowestSet8Bit((mask)>>8)+8)\r
+#define LowestSet32Bit(mask) ((mask)&0xffff?LowestSet16Bit(mask):LowestSet16Bit((mask)>>16)+16)\r
+\r
+\r
+// Character modifcation double height:\r
+enum enumDblHeight {\r
+    dblh_Normal=0x00000000, // normal height\r
+    dblh_Top   =0x04000000, // upper half character\r
+    dblh_Bottom=0x08000000  // lower half character\r
+};\r
+// Character modifcation double width:\r
+enum enumDblWidth {\r
+    dblw_Normal=0x00000000, // normal width\r
+    dblw_Left  =0x10000000, // left half character\r
+    dblw_Right =0x20000000  // right half character\r
+};\r
+\r
+// Teletext colors\r
+enum enumTeletextColor {\r
+    // level 1:\r
+    ttcBlack=0,\r
+    ttcRed=1,\r
+    ttcGreen=2,\r
+    ttcYellow=3,\r
+    ttcBlue=4,\r
+    ttcMagenta=5,\r
+    ttcCyan=6,\r
+    ttcWhite=7,\r
+    // level 2.5:\r
+    ttcTransparent=8,\r
+    ttcHalfRed=9,\r
+    ttcHalfGreen=10,\r
+    ttcHalfYellow=11,\r
+    ttcHalfBlue=12,\r
+    ttcHalfMagenta=13,\r
+    ttcHalfCyan=14,\r
+    ttcGrey=15,\r
+    // unnamed, level 2.5:\r
+    ttcColor16=16, ttcColor17=17, ttcColor18=18, ttcColor19=19,\r
+    ttcColor20=20, ttcColor21=21, ttcColor22=22, ttcColor23=23,\r
+    ttcColor24=24, ttcColor25=25, ttcColor26=26, ttcColor27=27,\r
+    ttcColor28=28, ttcColor29=29, ttcColor30=30, ttcColor31=31,\r
+    \r
+    ttcFirst=0, ttcLast=31\r
+};\r
+inline enumTeletextColor& operator++(enumTeletextColor& c) { return c=enumTeletextColor(int(c)+1); }\r
+inline enumTeletextColor operator++(enumTeletextColor& c, int) { enumTeletextColor tmp(c); ++c; return tmp; }\r
+    \r
+class cTeletextChar {\r
+    // Wrapper class that represents a teletext character,\r
+    // including colors and effects. Should optimize back\r
+    // to 4 byte unsigned int on compile.\r
+    \r
+protected:\r
+    unsigned int c;\r
+\r
+    static const unsigned int CHAR             = 0x000000FF;\r
+    // character code\r
+    static const unsigned int CHARSET          = 0x00001F00;\r
+    // character set code, see below\r
+    static const unsigned int BOXOUT           = 0x00004000;\r
+    // 'boxed' mode hidden area\r
+    static const unsigned int DIRTY            = 0x00008000;\r
+    // 'dirty' bit - internal marker only\r
+    static const unsigned int FGCOLOR          = 0x001F0000;\r
+    // 5-bit foreground color code, 3 bit used for now\r
+    static const unsigned int BGCOLOR          = 0x03E00000;\r
+    // 5-bit background color code, 3 bit used for now\r
+    static const unsigned int DBLHEIGHT        = 0x0C000000;\r
+    // show double height\r
+    static const unsigned int DBLWIDTH         = 0x30000000;\r
+    // show double width (todo)\r
+    static const unsigned int CONCEAL          = 0x40000000;\r
+    // character concealed\r
+    static const unsigned int BLINK            = 0x80000000;\r
+    // blinking character\r
+\r
+    cTeletextChar(unsigned int cc) { c=cc; }\r
+\r
+public:\r
+    cTeletextChar() { c=0; }\r
+    \r
+    // inline helper functions:\r
+    // For each parameter encoded into the 32-bit int, there is\r
+    // a Get...() to read, a Set...() to write, and a To...() to\r
+    // return a modified copy\r
+    \r
+    inline unsigned char GetChar() \r
+        { return c&CHAR; }\r
+    inline void SetChar(unsigned char chr)\r
+        { c=(c&~CHAR)|chr; }\r
+    inline cTeletextChar ToChar(unsigned char chr)\r
+        { return cTeletextChar((c&~CHAR)|chr); }\r
+        \r
+    inline enumCharsets GetCharset() \r
+        { return (enumCharsets)(c&CHARSET); }\r
+    inline void SetCharset(enumCharsets charset) \r
+        { c=(c&~CHARSET)|charset; }\r
+    inline cTeletextChar ToCharset(enumCharsets charset) \r
+        { return cTeletextChar((c&~CHARSET)|charset); }\r
+    \r
+    inline enumTeletextColor GetFGColor() \r
+        { return (enumTeletextColor)((c&FGCOLOR) >> LowestSet32Bit(FGCOLOR)); }\r
+    inline void SetFGColor(enumTeletextColor fgc) \r
+        { c=(c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR)); }\r
+    inline cTeletextChar ToFGColor(enumTeletextColor fgc) \r
+        { return cTeletextChar((c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR))); }\r
+    \r
+    inline enumTeletextColor GetBGColor() \r
+        { return (enumTeletextColor)((c&BGCOLOR) >> LowestSet32Bit(BGCOLOR)); }\r
+    inline void SetBGColor(enumTeletextColor bgc) \r
+        { c=(c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR)); }\r
+    inline cTeletextChar ToBGColor(enumTeletextColor bgc) \r
+        { return cTeletextChar((c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR))); }\r
+    \r
+    inline bool GetBoxedOut() \r
+        { return c&BOXOUT; }\r
+    inline void SetBoxedOut(bool BoxedOut) \r
+        { c=(BoxedOut)?(c|BOXOUT):(c&~BOXOUT); }\r
+    inline cTeletextChar ToBoxedOut(bool BoxedOut) \r
+        { return cTeletextChar((BoxedOut)?(c|BOXOUT):(c&~BOXOUT)); }\r
+    \r
+    inline bool GetDirty() \r
+        { return c&DIRTY; }\r
+    inline void SetDirty(bool Dirty) \r
+        { c=(Dirty)?(c|DIRTY):(c&~DIRTY); }\r
+    inline cTeletextChar ToDirty(bool Dirty) \r
+        { return cTeletextChar((Dirty)?(c|DIRTY):(c&~DIRTY)); }\r
+    \r
+    inline enumDblHeight GetDblHeight() \r
+        { return (enumDblHeight)(c&DBLHEIGHT); }\r
+    inline void SetDblHeight(enumDblHeight dh) \r
+        { c=(c&~(DBLHEIGHT)) | dh; }\r
+    inline cTeletextChar ToDblHeight(enumDblHeight dh) \r
+        { return cTeletextChar((c&~(DBLHEIGHT)) | dh); }\r
+    \r
+    inline enumDblWidth GetDblWidth() \r
+        { return (enumDblWidth)(c&DBLWIDTH); }\r
+    inline void SetDblWidth(enumDblWidth dw) \r
+        { c=(c&~(DBLWIDTH)) | dw; }\r
+    inline cTeletextChar ToDblWidth(enumDblWidth dw) \r
+        { return cTeletextChar((c&~(DBLWIDTH)) | dw); }\r
+    \r
+    inline bool GetConceal() \r
+        { return c&CONCEAL; }\r
+    inline void SetConceal(bool Conceal) \r
+        { c=(Conceal)?(c|CONCEAL):(c&~CONCEAL); }\r
+    inline cTeletextChar ToConceal(bool Conceal) \r
+        { return cTeletextChar((Conceal)?(c|CONCEAL):(c&~CONCEAL)); }\r
+    \r
+    inline bool GetBlink() \r
+        { return c&BLINK; }\r
+    inline void SetBlink(bool Blink) \r
+        { c=(Blink)?(c|BLINK):(c&~BLINK); }\r
+    inline cTeletextChar ToBlink(bool Blink) \r
+        { return cTeletextChar((Blink)?(c|BLINK):(c&~BLINK)); }\r
+        \r
+    bool operator==(cTeletextChar &chr) { return c==chr.c; }\r
+    bool operator!=(cTeletextChar &chr) { return c!=chr.c; }\r
+};\r
+/* from osdteletext end*/\r
+\r
+class VTeletextView;\r
+\r
+/* Decoder of teletext matrial present in Data stream for VBI reinsertion more or less according to EBU specs*/ \r
+class TeletextDecoderVBIEBU: public DrainTarget {\r
+public:\r
+    TeletextDecoderVBIEBU();\r
+    virtual ~TeletextDecoderVBIEBU();\r
+\r
+    virtual long long SetStartOffset(long long curreftime, bool *rsync);\r
+    virtual void ResetTimeOffsets();\r
+\r
+    void ResetDecoder();\r
+    void setKeyinDigits(char digits[3],bool inKeying);\r
+    void setPage(unsigned int newpage);\r
+    int getPage() {return selectedpage;};\r
+    void setRecordigMode(bool isrecord) {isrecording=isrecord;};\r
+    int *getSubtitlePages() {return record_pages;};\r
+\r
+\r
+    virtual void PrepareMediaSample(const MediaPacketList& mplist, UINT samplepos);\r
+    virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos);\r
+\r
+    void registerTeletextView(VTeletextView* view) {txtview=view;};\r
+    void unRegisterTeletextView(VTeletextView* view) {if (txtview==view) txtview=NULL;};\r
+    VTeletextView* getTeletxtView() {return txtview;};\r
+\r
+    cTeletextChar getChar(int x, int y) {\r
+        // Read character content from page\r
+        if (x<0 || x>=40 || y<0 || y>=25) {\r
+            Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds read access to teletext page");\r
+            return cTeletextChar();\r
+        }\r
+        return Page[x][y].ToDirty(false);\r
+    }\r
+    bool isDirty(int x, int y) {\r
+        if (x<0 || x>=40 || y<0 || y>=25) {\r
+            Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds dirty access to teletext page");\r
+            return false;\r
+        }\r
+        return Page[x][y].GetDirty();\r
+    }\r
+    void setChar(int x, int y, cTeletextChar c) {\r
+        // Set character at given location\r
+        \r
+        if (x<0 || x>=40 || y<0 || y>=25) {\r
+            Log::getInstance()->log("TeletextDecoderVBIEBU", Log::DEBUG, "Warning: out of bounds write access to teletext page");\r
+            return;\r
+        }\r
+        if (getChar(x,y) != c) {\r
+            Page[x][y]=c.ToDirty(true);\r
+            dirty=true; \r
+        }           \r
+    }\r
+\r
+\r
+protected:\r
+    void DecodeTeletext(const UCHAR* buffer, unsigned int field);\r
+    void RenderTeletextCode(bool renderfirstlineonly);\r
+    void CleanPage();\r
+\r
+    int selectedpage;\r
+    int lang;\r
+    int flags;\r
+    UCHAR curpage[25][40]; //Line DataCache\r
+    cTeletextChar Page[40][25];\r
+    char keyindigits[3];\r
+\r
+\r
+    // Font Code pages\r
+    int FirstG0CodePage;  // 7-bit number, lower 3 bits ignored\r
+    int SecondG0CodePage; // 7-bit number\r
\r
+    bool ourpage;\r
+    bool dirty;\r
+    bool gotcha;\r
+    bool inkeying;\r
+    bool isrecording;\r
+    int record_pages[10];//Only 10 Pages per record;\r
+    unsigned int firstlineupdate;\r
+    VTeletextView *txtview;\r
+private:\r
+    MediaPacket mediapacket;\r
+    \r
+    \r
+\r
+};\r
+\r
+#endif\r
diff --git a/teletxt/COPYING b/teletxt/COPYING
new file mode 100644 (file)
index 0000000..5b6e7c6
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/teletxt/README b/teletxt/README
new file mode 100644 (file)
index 0000000..865dc52
--- /dev/null
@@ -0,0 +1,98 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by:                  Marcel Wiesweg <marcel.wiesweg@gmx.de>
+
+Project's homepage:          http://www.wiesweg-online.de/linux/vdr
+
+Latest version available at: http://www.wiesweg-online.de/linux/vdr
+
+See the file COPYING for license information.
+
+Description:
+
+Osd-Teletext displays the teletext directly on the OSD.
+Both sound and video are played in the background. 
+
+
+Keys:
+     1,...,9: insert page number
+     Up:      page+
+     Down:    page-
+     Right:   sub page+
+     Left:    sub page-
+     Back:    close teletext plugin
+     
+   All other user interaction ("Actions") is configurably assigned to the other
+   available keys.
+   You can e.g. configure that you jump to page 100 when you press Red.
+   In this example, the Action "Jump to 100" is assigned to key "Red".
+   Have a look at the plugin's setup page to learn the current assignment
+   and adapt it to your needs.
+   
+   Available Keys: Blue, Red, Yellow, Green, Play, Stop, FastFwd, FastRwd
+   Actions: "Zoom", "Half page", "Switch channel", "Switch background",
+            "Jump to..." a specific page.
+            
+   Description of the actions:
+     Zoom:          Zoom to upper half/lower half/back to full page
+     Half Page:     Reduce OSD window to the lower half of the screen and display upper half/lower half/back to full size
+     Switch channel:Show pages of a channel different from the one currently tuned to.
+                    This does _not_ include any tuning or channel switching with vdr's core. 
+                    You must have tuned to the channel chosen some time before so that the pages have been stored on disk.
+                    When you press the key associated with that action, you are asked for the channel number.
+                    Press OK after you entered it with the number keys.
+     Jump to...:    Jumps to the page you configure.
+     Switch background: Changes the in the setup configurable background color immediately
+                        to black and back to your degree of transparency.
+                        
+   How to configure the key bindings:
+   In the plugins setup menu, you can assign one of actions to each key.
+   You can choose freely which actions you need, you are not forced to assign
+   an action to a key at all if you do not need it.
+   If you select "Jump to...", specify the page number in the line immediately below.
+   
+   
+Other Setup options:
+   Background transparency: 
+               number between 0 (transparent) and 255 (black). Default is 127 (also used by VDR)
+   Show Clock: Toggles whether an additional clock is drawn approximately every second.
+               The clock shows the current system time, not any time broadcast via teletext.
+               Let VDR set the system time from a transponder to have the exact time.
+   Auto-update pages: 
+               Continuously checks whether a page has changed and updates it if yes.
+   OSD width, OSD height: 
+               Adjusts the width and height of the OSD independent from VDR's settings.
+               The valid range is 40 to 56 for the width and 12 to 21 for the height.
+   Minimum user inactivity: 
+               Sets a timeout (in minutes) for user inactivity. When this timespan has elapsed
+               and the user did not press any keys, the plugin will be closed. Set to 0 to disable this.
+               Note that disabling timeout will also effectively disable VDR's auto-shutdown feature
+               as long as the plugin is active.
+   Key bindings:      See above.
+   
+Command line options:
+   A few settings are given on the command line rather than in the setup menu.
+   Available options:
+   
+     -d        --directory=DIR    The directory where the temporary
+                                  files will be stored.
+                                  (standard value: /vtx, recommended: /tmp/vtx
+                                   or /var/cache/vdr/osdteletext.)
+                                  Ensure that the directory exists and is writable.
+     -n        --max-cache=NUM    Maximum size in megabytes of cache used
+                                  to store the pages on the harddisk.
+                                  (standard value: a calculated value below 50 MB)
+     -s        --cache-system=SYS Set the cache system to be used.
+                                  Choose "legacy" for the traditional
+                                  one-file-per-page system.
+                                  Default is "packed" for the 
+                                  one-file-for-a-few-pages system.
+
+Colors:
+  On all sorts of output devices which are not limited as to color depth
+  the original teletext colors will be displayed. (Only difference: Cyan is used instead of 
+  white to make reading easier).
+  On the classic full-featured DVB card and other limited devices, the colors will be reduced to four.
+  The mapping is currently optimized for German ARD, ZDF and RTL. If you are for some reason
+  really and definitely not satisfied with my choices, edit colormapping.h and recompile.
+
diff --git a/teletxt/tables.h b/teletxt/tables.h
new file mode 100644 (file)
index 0000000..08fe344
--- /dev/null
@@ -0,0 +1,112 @@
+/* This file is copied from Ralph Metzler's vbidecode package. */
+
+/* 
+    tables.h - some data conversion tables for vbidecode
+*/
+
+#ifndef _TABLES_H
+#define _TABLES_H
+
+unsigned char invtab[256] = {
+  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 
+  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 
+  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 
+  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 
+  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 
+  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 
+  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 
+  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 
+  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 
+  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 
+  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 
+  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 
+  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 
+  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 
+  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 
+  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 
+  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 
+  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 
+  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 
+  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 
+  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 
+  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 
+  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 
+  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 
+  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 
+  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 
+  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 
+  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 
+  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 
+  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 
+  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 
+  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 
+};
+
+unsigned char unhamtab[256] = {
+  0x01, 0xff, 0x81, 0x01, 0xff, 0x00, 0x01, 0xff, 
+  0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07, 
+  0xff, 0x00, 0x01, 0xff, 0x00, 0x80, 0xff, 0x00, 
+  0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff, 
+  0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07, 
+  0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x87, 
+  0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff, 
+  0x86, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07, 
+  0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09, 
+  0x02, 0x82, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff, 
+  0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff, 
+  0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x83, 0x03, 
+  0x04, 0xff, 0xff, 0x05, 0x84, 0x04, 0x04, 0xff, 
+  0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07, 
+  0xff, 0x05, 0x05, 0x85, 0x04, 0xff, 0xff, 0x05, 
+  0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff, 
+  0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09, 
+  0x0a, 0xff, 0xff, 0x0b, 0x8a, 0x0a, 0x0a, 0xff, 
+  0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff, 
+  0xff, 0x0b, 0x0b, 0x8b, 0x0a, 0xff, 0xff, 0x0b, 
+  0x0c, 0x8c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff, 
+  0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07, 
+  0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x8d, 0x0d, 
+  0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff, 
+  0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x89, 
+  0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09, 
+  0x88, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09, 
+  0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff, 
+  0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09, 
+  0x0f, 0xff, 0x8f, 0x0f, 0xff, 0x0e, 0x0f, 0xff, 
+  0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff, 
+  0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x8e, 0xff, 0x0e, 
+};
+
+unsigned char cct2vtx_table[] = 
+  { 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27,
+    0x28, 0x29, 0x2a, 0x2b,
+    0x2c, 0x2d, 0x2e, 0x2f,
+
+    0x30, 0x31, 0x32, 0x33,
+    0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3a, 0x3b,
+    0x3c, 0x3d, 0x3e, 0xef,
+
+    0x40, 0x41, 0x42, 0x43,
+    0x44, 0x45, 0x46, 0x47,
+    0x48, 0x49, 0x4a, 0x4b,
+    0x4c, 0x4d, 0x4e, 0x4f,
+
+    0x50, 0x51, 0x52, 0x53,
+    0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x5a, 0x5b,
+    0x5c, 0x5d, 0x5e, 0x5f,
+
+    0x60, 0x61, 0x62, 0x63,
+    0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x6a, 0x6b,
+    0x6c, 0x6d, 0x6e, 0x6f,
+
+    0x70, 0x71, 0x72, 0x73,
+    0x74, 0x75, 0x76, 0x77,
+    0x78, 0x79, 0x7a, 0x7b,
+    0x7c, 0x7d, 0x7e, 0x7f
+  }; 
+
+#endif
diff --git a/teletxt/txtfont.cc b/teletxt/txtfont.cc
new file mode 100644 (file)
index 0000000..438ff7d
--- /dev/null
@@ -0,0 +1,3371 @@
+#include "txtfont.h"
+
+unsigned int TXT_Mask[11]= {
+   0x0000,  // ************ ****
+   0x39C0,  // **###**###** ****
+   0x39C0,  // **###**###** ****
+   0x0000,  // ************ ****
+   0x39C0,  // **###**###** ****
+   0x39C0,  // **###**###** ****
+   0x0000,  // ************ ****
+   0x39C0,  // **###**###** ****
+   0x39C0,  // **###**###** ****
+   0x0000   // ************ ****
+  };
+
+unsigned int TXT_Font[][11]= {
+  { // 0x20 = Leerzeichen
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x21 = !
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x22 = "
+   0x0000,  // ************ ****
+   0x39C0,  // **###**###** ****
+   0x18C0,  // ***##***##** ****
+   0x3180,  // **##***##*** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x23 = # = NC 
+   0x0000,  // ************ ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x0000   // ************ ****
+  },
+  { // 0x24 = $ = NC
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x6660,  // *##**##**##* ****
+   0x6600,  // *##**##***** ****
+   0x3FC0,  // **########** ****
+   0x0660,  // *****##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+  },
+  { // 0x25 = %
+   0x0000,  // ************ ****
+   0x70C0,  // *###****##** ****
+   0xD980,  // ##*##**##*** ****
+   0x7300,  // *###**##**** ****
+   0x0600,  // *****##***** ****
+   0x0CE0,  // ****##**###* ****
+   0x19B0,  // ***##**##*## ****
+   0x30E0,  // **##****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x26 = & 
+   0x0000,  // ************ ****
+   0x1E00,  // ***####***** ****
+   0x3300,  // **##**##**** ****
+   0x3300,  // **##**##**** ****
+   0x1E00,  // ***####***** ****
+   0x3330,  // **##**##**## ****
+   0x61C0,  // *##****###** ****
+   0x3F30,  // **######**## ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x27 = '
+   0x0000,  // ************ ****
+   0x0700,  // *****###**** ****
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x28 = (
+   0x0000,  // ************ ****
+   0x0700,  // *****###**** ****
+   0x0C00,  // ****##****** ****
+   0x1800,  // ***##******* ****
+   0x1800,  // ***##******* ****
+   0x1800,  // ***##******* ****
+   0x0C00,  // ****##****** ****
+   0x0700,  // *****###**** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x29 = )
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0300,  // ******##**** ****
+   0x0180,  // *******##*** ****
+   0x0180,  // *******##*** ****
+   0x0180,  // *******##*** ****
+   0x0300,  // ******##**** ****
+   0x0E00,  // ****###***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x2A = *
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x6660,  // *##**##**##* ****
+   0x36C0,  // **##*##*##** ****
+   0x0F00,  // ****####**** ****
+   0x36C0,  // **##*##*##** ****
+   0x6660,  // *##**##**##* ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x2B = +
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x2C = ,
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3800,  // **###******* ****
+   0x1800,  // ***##******* ****
+   0x3000,  // **##******** ****
+  },
+  { // 0x2D = -
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x2E = .
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x1800,  // ***##******* ****
+   0x1800,  // ***##******* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x2F = /
+   0x0000,  // ************ ****
+   0x00C0,  // ********##** ****
+   0x0180,  // *******##*** ****
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0C00,  // ****##****** ****
+   0x1800,  // ***##******* ****
+   0x3000,  // **##******** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+
+  { // 0x30 = 0
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x38E0,  // **###***###* ****
+   0x38E0,  // **###***###* ****
+   0x38E0,  // **###***###* ****
+   0x38E0,  // **###***###* ****
+   0x38E0,  // **###***###* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x31 = 1
+   0x0000,  // ************ ****
+   0x0700,  // *****###**** ****
+   0x1F00,  // ***#####**** ****
+   0x0700,  // *****###**** ****
+   0x0700,  // *****###**** ****
+   0x0700,  // *****###**** ****
+   0x0700,  // *****###**** ****
+   0x0700,  // *****###**** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x32 = 2
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x30E0,  // **##****###* ****
+   0x00E0,  // ********###* ****
+   0x01C0,  // *******###** ****
+   0x0780,  // *****####*** ****
+   0x1E00,  // ***####***** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x33 = 3
+   0x0000,  // ************ ****
+   0x3FE0,  // **#########* ****
+   0x00C0,  // ********##** ****
+   0x0080,  // *******##*** ****
+   0x07E0,  // *****######* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x34 = 4
+   0x0000,  // ************ ****
+   0x00E0,  // ********###* ****
+   0x03C0,  // ******####** ****
+   0x0700,  // *****###**** ****
+   0x1C00,  // ***###****** ****
+   0x38E0,  // **###***###* ****
+   0x3FE0,  // **#########* ****
+   0x00E0,  // ********###* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x35 = 5
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3FC0,  // **########** ****
+   0x00E0,  // ********###* ****
+   0x30E0,  // **##****###* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x36 = 6
+   0x0000,  // ************ ****
+   0x0700,  // *****###**** ****
+   0x0E00,  // ****###***** ****
+   0x1C00,  // ***###****** ****
+   0x3FC0,  // **########** ****
+   0x3860,  // **###****##* ****
+   0x3860,  // **###****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x37 = 7
+   0x0000,  // ************ ****
+   0x7FE0,  // *##########* ****
+   0x01C0,  // *******###** ****
+   0x0380,  // ******###*** ****
+   0x0700,  // *****###**** ****
+   0x0E00,  // ****###***** ****
+   0x1C00,  // ***###****** ****
+   0x3800,  // **###******* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x38 = 8
+   0x0000,  // ************ ****
+   0x0F80,  // ****#####*** ****
+   0x38E0,  // **###***###* ****
+   0x38E0,  // **###***###* ****
+   0x0F80,  // ****#####*** ****
+   0x38E0,  // **###***###* ****
+   0x38E0,  // **###***###* ****
+   0x0F80,  // ****#####*** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x39 = 9
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x30E0,  // **##****###* ****
+   0x30E0,  // **##****###* ****
+   0x1FC0,  // ***#######** ****
+   0x0380,  // ******###*** ****
+   0x0700,  // *****###**** ****
+   0x0E00,  // ****###***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x3A = :
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x0000,  // ************ ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x3B = ;
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x1800,  // ***##******* ****
+  },
+  { // 0x3C = <
+   0x0000,  // ************ ****
+   0x00E0,  // ********###* ****
+   0x0380,  // ******###*** ****
+   0x0E00,  // ****###***** ****
+   0x3800,  // **###******* ****
+   0x0E00,  // ****###***** ****
+   0x0380,  // ******###*** ****
+   0x00E0,  // ********###* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x3D = =
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x3E = >
+   0x0000,  // ************ ****
+   0x7000,  // *###******** ****
+   0x1C00,  // ***###****** ****
+   0x0700,  // *****###**** ****
+   0x01C0,  // *******###** ****
+   0x0700,  // *****###**** ****
+   0x1C00,  // ***###****** ****
+   0x7000,  // *###******** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+  { // 0x3F = ?
+   0x0000,  // ************ ****
+   0x1F80,  // ***######*** ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x0180,  // *******##*** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+  },
+
+  { // 0x40 = Â§ = NC
+   0x0000,  // ************ ****
+   0x1F80,  // ***######*** ****
+   0x30C0,  // **##****##** ****
+   0x3000,  // **##******** ****
+   0x1F80,  // ***######*** ****
+   0x30C0,  // **##****##** ****
+   0x1F80,  // ***######*** ****
+   0x00C0,  // ********##** ****
+   0x30C0,  // **##****##** ****
+   0x1F80   // ***######*** ****
+  },
+  { // 0x41 = A
+   0x0000,  // ************ ****
+   0x0F00,  // ****####**** ****
+   0x1980,  // ***##**##*** ****
+   0x30C0,  // **##****##** ****
+   0x6060,  // *##******##* ****
+   0x7FE0,  // *##########* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x42 = B
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FC0,  // **########** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x43 = C
+   0x0000,  // ************ ****
+   0x0FC0,  // ****######** ****
+   0x1860,  // ***##****##* ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x1860,  // ***##****##* ****
+   0x0FC0,  // ****######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x44 = D
+   0x0000,  // ************ ****
+   0x3F80,  // **#######*** ****
+   0x30C0,  // **##****##** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30C0,  // **##****##** ****
+   0x3F80,  // **#######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x45 = E
+   0x0000,  // ************ ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3F80,  // **#######*** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x46 = F
+   0x0000,  // ************ ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3F80,  // **#######*** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x47 = G
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x33E0,  // **##**#####* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x48 = H
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x7FE0,  // *##########* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x49 = I
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x4A = J
+   0x0000,  // ************ ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x4B = K
+   0x0000,  // ************ ****
+   0x30E0,  // **##****###* ****
+   0x3180,  // **##***##*** ****
+   0x3700,  // **##*###**** ****
+   0x3C00,  // **####****** ****
+   0x3700,  // **##*###**** ****
+   0x3180,  // **##***##*** ****
+   0x30E0,  // **##****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x4C = L
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x4D = M
+   0x0000,  // ************ ****
+   0x70E0,  // *###****###* ****
+   0x79E0,  // *####**####* ****
+   0x6F60,  // *##*####*##* ****
+   0x6660,  // *##**##**##* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x4E = N
+   0x0000,  // ************ ****
+   0x7060,  // *###*****##* ****
+   0x7860,  // *####****##* ****
+   0x6C60,  // *##*##***##* ****
+   0x6660,  // *##**##**##* ****
+   0x6360,  // *##***##*##* ****
+   0x61E0,  // *##****####* ****
+   0x60E0,  // *##*****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x4F = O
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+
+  { // 0x50 = P
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FC0,  // **########** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x51 = Q
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3360,  // **##**##*##* ****
+   0x1FC0,  // ***#######** ****
+   0x0180,  // *******##*** ****
+   0x00E0   // ********###* ****
+  },
+  { // 0x52 = R
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FC0,  // **########** ****
+   0x3300,  // **##**##**** ****
+   0x31C0,  // **##***###** ****
+   0x30E0,  // **##****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x53 = S
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x54 = T
+   0x0000,  // ************ ****
+   0x7FE0,  // *##########* ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x55 = U
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x56 = V
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x1980,  // ***##**##*** ****
+   0x0F00,  // ****####**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x57 = W
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x6660,  // *##**##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x6F60,  // *##*####*##* ****
+   0x39C0,  // **###**###** ****
+   0x30C0,  // **##****##** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x58 = X
+   0x0000,  // ************ ****
+   0x30C0,  // **##****##** ****
+   0x1980,  // ***##**##*** ****
+   0x0F00,  // ****####**** ****
+   0x0600,  // *****##***** ****
+   0x0F00,  // ****####**** ****
+   0x1980,  // ***##**##*** ****
+   0x30C0,  // **##****##** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x59 = Y
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x30C0,  // **##****##** ****
+   0x1980,  // ***##**##*** ****
+   0x0F00,  // ****####**** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x5A = Z
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0180,  // *******##*** ****
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0C00,  // ****##****** ****
+   0x1800,  // ***##******* ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x5B = Ã„ = NC
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x5C = Ã– = NC
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x5D = Ãœ = NC
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x5E = ^ = NC
+   0x0600,  // *****##***** ****
+   0x0F00,  // ****####**** ****
+   0x1980,  // ***##**##*** ****
+   0x30C0,  // **##****##** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x5F = _ = NC
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x7FE0   // *##########* ****
+  },
+
+  { // 0x60 = Â° = NC
+   0x0000,  // ************ ****
+   0x0000,  // *****####*** ****
+   0x0000,  // ****##**##** ****
+   0x0000,  // *****####*** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x61 = a
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x62 = b
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x37C0,  // **##*#####** ****
+   0x3860,  // **###****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x63 = c
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0FE0,  // ****#######* ****
+   0x1800,  // ***##******* ****
+   0x3000,  // **##******** ****
+   0x1800,  // ***##******* ****
+   0x0FE0,  // ****#######* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x64 = d
+   0x0000,  // ************ ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x1F60,  // ***#####*##* ****
+   0x30E0,  // **##****###* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FE0,  // ***########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x65 = e
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x66 = f
+   0x0000,  // ************ ****
+   0x07E0,  // *****######* ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x3F80,  // **#######*** ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x67 = g
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x1F60,  // ***#####*##* ****
+   0x30E0,  // **##****###* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0060,  // *********##* ****
+   0x1FC0   // ***#######** ****
+  },
+  { // 0x68 = h
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x37C0,  // **##*#####** ****
+   0x3860,  // **###****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x69 = i
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x1F80,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x6A = j
+   0x0000,  // ************ ****
+   0x00E0,  // ********###* ****
+   0x0000,  // ************ ****
+   0x01E0,  // *******####* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x0060,  // *********##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0   // ***#######** ****
+  },
+  { // 0x6B = k
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x30E0,  // **##****###* ****
+   0x3180,  // **##***##*** ****
+   0x3E00,  // **#####***** ****
+   0x3180,  // **##***##*** ****
+   0x30E0,  // **##****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x6C = l
+   0x0000,  // ************ ****
+   0x1E00,  // ***####***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x6D = m
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x6DC0,  // *##*##*###** ****
+   0x6660,  // *##**##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x6E = n
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x37C0,  // **##*#####** ****
+   0x3860,  // **###****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x6F = o
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+
+  { // 0x70 = p
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x37C0,  // **##*#####** ****
+   0x3860,  // **###****##* ****
+   0x3060,  // **##*****##* ****
+   0x3860,  // **###****##* ****
+   0x37C0,  // **##*#####** ****
+   0x3000,  // **##******** ****
+   0x3000   // **##******** ****
+  },
+  { // 0x71 = q
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x1EC0,  // ***####*##** ****
+   0x31C0,  // **##***###** ****
+   0x30C0,  // **##****##** ****
+   0x31C0,  // **##***###** ****
+   0x1EC0,  // ***####*##** ****
+   0x00C0,  // ********##** ****
+   0x01E0   // *******####* ****
+  },
+  { // 0x72 = r
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x33E0,  // **##**#####* ****
+   0x3C00,  // **####****** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x73 = s
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0060,  // *********##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x74 = t
+   0x0000,  // ************ ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x3F80,  // **#######*** ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x0C00,  // ****##****** ****
+   0x07E0,  // *****######* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x75 = u
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x76 = v
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x30C0,  // **##****##** ****
+   0x1980,  // ***##**##*** ****
+   0x0F00,  // ****####**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x77 = w
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x6660,  // *##**##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x36C0,  // **##*##*##** ****
+   0x2980,  // ***##**##*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x78 = x
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x70E0,  // *###****###* ****
+   0x1980,  // ***##**##*** ****
+   0x0F00,  // ****####**** ****
+   0x1980,  // ***##**##*** ****
+   0x70E0,  // *###****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x79 = y
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x18C0,  // ***##***##** ****
+   0x0D80,  // ****##*##*** ****
+   0x0700,  // *****###**** ****
+   0x0600,  // *****##***** ****
+   0x0C00,  // ****##****** ****
+   0x3800   // **###******* ****
+  },
+  { // 0x7A = z
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3FE0,  // **#########* ****
+   0x0180,  // *******##*** ****
+   0x0700,  // *****###**** ****
+   0x0C00,  // ****##****** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x7B = Ã¤ = NC
+   0x0000,  // ************ ****
+   0x3180,  // **##***##*** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x7C = Ã¶ = NC
+   0x0000,  // ************ ****
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x7D = Ã¼ = NC
+   0x0000,  // ************ ****
+   0x10C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x7E = ÃŸ = NC
+   0x0000,  // ************ ****
+   0x0F80,  // ****#####*** ****
+   0x18C0,  // ***##***##** ****
+   0x30C0,  // **##****##** ****
+   0x3380,  // **##**###*** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x33C0,  // **##**####** ****
+   0x3000,  // **##******** ****
+   0x3000   // **##******** ****
+  },
+  { // 0x7F = Block
+   0x0000,  // ************ ****
+   0x7FE0,  // *##########* ****
+   0x7FE0,  // *##########* ****
+   0x7FE0,  // *##########* ****
+   0x7FE0,  // *##########* ****
+   0x7FE0,  // *##########* ****
+   0x7FE0,  // *##########* ****
+   0x7FE0,  // *##########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+
+  { // 0x80 = 
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x63E0,  // *##***#####* ****
+   0x6660,  // *##**##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x63E0,  // *##***#####* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000   // ************ ****
+  },
+  { // 0x81 = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x82 = 
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x7000,  // *###******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3180,  // **##***##*** ****
+   0x0300,  // ******##**** ****
+   0x0660,  // *****##**##* ****
+   0x07E0,  // *****######* ****
+   0x0060   // *********##* ****
+  },
+  { // 0x83 = 
+   0x0000,  // ************ ****
+   0x0FC0,  // ****######** ****
+   0x1860,  // ***##****##* ****
+   0x0C00,  // ****##****** ****
+   0x3F00,  // **######**** ****
+   0x0C00,  // ****##****** ****
+   0x3E60,  // **#####**##* ****
+   0x33C0,  // **##**####** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x84 = 
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x6660,  // *##**##**##* ****
+   0x6600,  // *##**##***** ****
+   0x3FC0,  // **########** ****
+   0x0660,  // *****##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0000   // ************ ****
+  },
+  { // 0x85 = 
+   0x07F0,  // *****####### ****
+   0x0C00,  // ****##****** ****
+   0x19F0,  // ***##**##### ****
+   0x1800,  // ***##******* ****
+   0x19F0,  // ***##**##### ****
+   0x1800,  // ***##******* ****
+   0x19F0,  // ***##**##### ****
+   0x0C00,  // ****##****** ****
+   0x07F0,  // *****####### ****
+   0x0000   // ************ ****
+  },
+  { // 0x86 = 
+   0xFFC0,  // ##########** ****
+   0x1C60,  // ***###***##* ****
+   0x0830,  // ****#*****## ****
+   0x7F30,  // *#######**## ****
+   0x4130,  // *#*****#**## ****
+   0x7F30,  // *#######**## ****
+   0x0830,  // ****#*****## ****
+   0x1C60,  // ***###***##* ****
+   0xFFC0,  // ##########** ****
+   0x0000   // ************ ****
+  },
+  { // 0x87 = 
+   0xFFC0,  // ##########** ****
+   0x0060,  // *********##* ****
+   0x3E30,  // **#####***## ****
+   0x6330,  // *##***##**## ****
+   0x0E30,  // ****###***## ****
+   0x1830,  // ***##*****## ****
+   0x1830,  // ***##*****## ****
+   0x0060,  // *********##* ****
+   0xFFC0,  // ##########** ****
+   0x0000   // ************ ****
+  },
+  { // 0x88 = 
+   0x0000,  // ************ ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x3980,  // ***##**##*** ****
+   0x0000   // ************ ****
+  },
+  { // 0x89 = 
+   0x0000,  // ************ ****
+   0x7C00,  // *#####****** ****
+   0x0C00,  // ****##****** ****
+   0x3800,  // **###******* ****
+   0x0C00,  // ****##****** ****
+   0x7980,  // *####**##*** ****
+   0x0300,  // ******##**** ****
+   0x0660,  // *****##**##* ****
+   0x07E0,  // *****######* ****
+   0x0060   // *********##* ****
+  },
+  { // 0x8A = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x8B = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x1C00,  // ***###****** ****
+   0x7FF0,  // *########### ****
+   0x1C00,  // ***###****** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x8C = 
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x7000,  // *###******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x33C0,  // **##**####** ****
+   0x0660,  // *****##**##* ****
+   0x00C0,  // ********##** ****
+   0x0300,  // ******##**** ****
+   0x07E0   // *****######* ****
+  },
+  { // 0x8D = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0380,  // ******###*** ****
+   0xFFE0,  // ###########* ****
+   0x0380,  // ******###*** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x8E = 
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0F00,  // ****####**** ****
+   0x1F80,  // ***######*** ****
+   0x36C0,  // **##*##*##** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600   // *****##***** ****
+  },
+  { // 0x8F = 
+   0x0000,  // ************ ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x0000   // ************ ****
+  },
+
+  { // 0x90 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x3000,  // **##******** ****
+   0x3F80,  // **#######*** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x91 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x92 = 
+   0x0000,  // ************ ****
+   0x3180,  // **##***##*** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x93 = 
+   0x0000,  // ************ ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x0000   // ************ ****
+  },
+  { // 0x94 = 
+   0x0000,  // ************ ****
+   0x6060,  // *##******##* ****
+   0x30C0,  // **##****##** ****
+   0x1F80,  // ***######*** ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x1F80,  // ***######*** ****
+   0x30C0,  // **##****##** ****
+   0x6060,  // *##******##* ****
+   0x0000   // ************ ****
+  },
+  { // 0x95 = 
+   0xFFC0,  // ##########** ****
+   0x0060,  // *********##* ****
+   0xFF30,  // ########**## ****
+   0x0030,  // **********## ****
+   0xFF30,  // ########**## ****
+   0x0030,  // **********## ****
+   0xFF30,  // ########**## ****
+   0x0060,  // *********##* ****
+   0xFFC0,  // ##########** ****
+   0x0000   // ************ ****
+  },
+  { // 0x96 = 
+   0xFFC0,  // ##########** ****
+   0x0060,  // *********##* ****
+   0x3E30,  // **#####***## ****
+   0x4730,  // *#***###**## ****
+   0x4730,  // *#***###**## ****
+   0x7F30,  // *#######**## ****
+   0x3E30,  // **#####***## ****
+   0x0060,  // *********##* ****
+   0xFFC0,  // ##########** ****
+   0x0000   // ************ ****
+  },
+  { // 0x97 = 
+   0xFFC0,  // ##########** ****
+   0x0860,  // ****#****##* ****
+   0x1C30,  // ***###****## ****
+   0x0030,  // **********## ****
+   0x7F30,  // *#######**## ****
+   0x0030,  // **********## ****
+   0x1C30,  // ***###****## ****
+   0x0860,  // ****#****##* ****
+   0xFFC0,  // ##########** ****
+   0x0000   // ************ ****
+  },
+  { // 0x98 = 
+   0x0000,  // ************ ****
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x99 = 
+   0x0E00,  // ****###***** ****
+   0x1B00,  // ***##*##**** ****
+   0x0E00,  // ****###***** ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x9A = 
+   0x0000,  // ************ ****
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x9B = 
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x9C = 
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x9D = 
+   0x0700,  // *****###**** ****
+   0x0700,  // *****###**** ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x9E = 
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0x9F = _
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x7FE0   // *##########* ****
+  },
+
+
+  { // 0xA0 = 0x20a
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA1 = 0x21a 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA2 = 0x22a
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA3 = 0x23a 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA4 = 0x24a 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA5 = 0x25a 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA6 = 0x26a
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA7 = 0x27a
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA8 = 0x28a
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xA9 = 0x29a
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xAA = 0x2Aa 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xAB = 0x2Ba
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xAC = 0x2Ca
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xAD = 0x2Da
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xAE = 0x2Ea 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xAF = 0x2Fa 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+
+  { // 0xB0 = 0x30a
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB1 = 0x31a
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB2 = 0x32a 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB3 = 0x33a 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB4 = 0x34a 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB5 = 0x35a
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB6 = 0x36a 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB7 = 0x37a 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB8 = 0x38a 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xB9 = 0x39a 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xBA = 0x3Aa 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xBB = 0x3Ba 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xBC = 0x3Ca 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xBD = 0x3Da 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xBE = 0x3Ea 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+  { // 0xBF = 0x3Fa 
+   0xFFFF,  // ############ ****
+   0xFFFF,  // ############ ****
+   0xFFFF,  // ############ ****
+   0xFFFF,  // ############ ****
+   0xFFFF,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00   // ######****** ****
+  },
+
+  { // 0xC0 = 
+   0x0600,  // *****##***** ****
+   0x0C00,  // ****##****** ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x6060,  // *##******##* ****
+   0x7FE0,  // *##########* ****
+   0x6000,  // *##********* ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC1 = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000   // ************ ****
+  },
+  { // 0xC2 = 
+   0x0C00,  // ****##****** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC3 = 
+   0x0000,  // ************ ****
+   0x0FC0,  // ****######** ****
+   0x1860,  // ***##****##* ****
+   0x0C00,  // ****##****** ****
+   0x3F00,  // **######**** ****
+   0x0C00,  // ****##****** ****
+   0x3E60,  // **#####**##* ****
+   0x33C0,  // **##**####** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC4 = 
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x6660,  // *##**##**##* ****
+   0x6600,  // *##**##***** ****
+   0x3FC0,  // **########** ****
+   0x0660,  // *****##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x3F60,  // **########** ****
+   0x06C0,  // *****##***** ****
+   0x0000   // ************ ****
+  },
+  { // 0xC5 = 
+   0x3CC0,  // **####**##** ****
+   0x6780,  // *##**####*** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC6 = 
+   0x3C60,  // **####***##* ****
+   0x67C0,  // *##**#####** ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC7 = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC8 = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xC9 = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xCA = 
+   0x0C00,  // ****##****** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x1F80,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xCB = 
+   0x0000,  // ************ ****
+   0x0780,  // *****####*** ****
+   0x0CC0,  // ****##**##** ****
+   0x0780,  // *****####*** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xCC = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0FE0,  // ****#######* ****
+   0x1800,  // ***##******* ****
+   0x3000,  // **##******** ****
+   0x1800,  // ***##******* ****
+   0x0FE0,  // ****#######* ****
+   0x0300,  // ******##**** ****
+   0x0E00   // ****###***** ****
+  },
+  { // 0xCD = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0310,  // ******###*** ****
+   0xFFE0,  // ###########* ****
+   0x0310,  // ******###*** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xCE = 
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0F00,  // ****####**** ****
+   0x1F80,  // ***######*** ****
+   0x36C0,  // **##*##*##** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600   // *****##***** ****
+  },
+  { // 0xCF = 
+   0x0000,  // ************ ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x0000   // ************ ****
+  },
+
+  { // 0xD0 = 
+   0x0C00,  // ****##****** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD1 = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD2 = 
+   0x0E00,  // ****###***** ****
+   0x1B00,  // ***##*##**** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD3 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD4 = 
+   0x0000,  // ************ ****
+   0x1980,  // ***##**##*** ****
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x1F80,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD5 = 
+   0x1E60,  // ***####**##* ****
+   0x33C0,  // **##**####** ****
+   0x1F80,  // ***######*** ****
+   0x30C0,  // **##****##** ****
+   0x6060,  // *##******##* ****
+   0x7FE0,  // *##########* ****
+   0x6060,  // *##******##* ****
+   0x6060,  // *##******##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD6 = 
+   0x1E60,  // ***####**##* ****
+   0x33C0,  // **##**####** ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD7 = 
+   0x0000,  // ************ ****
+   0x0FC0,  // ****######** ****
+   0x1860,  // ***##****##* ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x1860,  // ***##****##* ****
+   0x0FC0,  // ****######** ****
+   0x0300,  // ******##**** ****
+   0x0E00   // ****###***** ****
+  },
+  { // 0xD8 = 
+   0x0700,  // *****###**** ****
+   0x0D80,  // ****##*##*** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xD9 = 
+   0x0700,  // *****###**** ****
+   0x0D80,  // ****##*##*** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xDA = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0FE0,  // ****#######* ****
+   0x1800,  // ***##******* ****
+   0x3000,  // **##******** ****
+   0x1800,  // ***##******* ****
+   0x0FE0,  // ****#######* ****
+   0x0300,  // ******##**** ****
+   0x0E00   // ****###***** ****
+  },
+  { // 0xDB = 
+   0x0000,  // ************ ****
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xDC = 
+   0x0700,  // *****###**** ****
+   0x0D80,  // ****##*##*** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xDD = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xDE = 
+   0x0F00,  // ****####**** ****
+   0x1980,  // ***##**##*** ****
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x1F80,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xDF = 
+   0x0000,  // ************ ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x7FE0,  // *##########* ****
+   0x1980,  // ***##**##*** ****
+   0x1980,  // ***##**##*** ****
+   0x0000   // ************ ****
+  },
+
+  { // 0xE0 = 
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE1 = 
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0600,  // *****##***** ****
+   0x1800,  // ***##******* ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x1F00,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE2 = 
+   0x0000,  // ************ ****
+   0x18C0,  // ***##***##** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE3 = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0FE0,  // ****#######* ****
+   0x1800,  // ***##******* ****
+   0x3000,  // **##******** ****
+   0x1800,  // ***##******* ****
+   0x0FE0,  // ****#######* ****
+   0x0300,  // ******##**** ****
+   0x0E00   // ****###***** ****
+  },
+  { // 0xE4 = 
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x6660,  // *##**##**##* ****
+   0x6600,  // *##**##***** ****
+   0x3FC0,  // **########** ****
+   0x0660,  // *****##**##* ****
+   0x6660,  // *##**##**##* ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0000   // ************ ****
+  },
+  { // 0xE5 = 
+   0x0000,  // ************ ****
+   0x3F80,  // **#######*** ****
+   0x6180,  // *##****##*** ****
+   0x6180,  // *##****##*** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x7FE0,  // *##########* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE6 = 
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE7 = 
+   0x1E60,  // ***####**##* ****
+   0x33C0,  // **##**####** ****
+   0x3860,  // **###****##* ****
+   0x3C60,  // **####***##* ****
+   0x3660,  // **##*##**##* ****
+   0x3360,  // **##**##*##* ****
+   0x31E0,  // **##***####* ****
+   0x30E0,  // **##****###* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE8 = 
+   0x1E60,  // ***####**##* ****
+   0x33C0,  // **##**####** ****
+   0x0000,  // ************ ****
+   0x37C0,  // **##*#####** ****
+   0x3860,  // **###****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xE9 = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xEA = 
+   0x0C00,  // ****##****** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xEB = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x7F80,  // *########*** ****
+   0x00C0,  // ********##** ****
+   0x3FC0,  // **########** ****
+   0x60C0,  // *##*****##** ****
+   0x3FE0,  // **#########* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xEC = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3000,  // **##******** ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xED = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x0E00,  // ****###***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x1F80,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xEE = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xEF = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x0000,  // ************ ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x30E0,  // **##****###* ****
+   0x1F60,  // ***#####*##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+
+  { // 0xF0 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF1 = 
+   0x0C00,  // ****##****** ****
+   0x0600,  // *****##***** ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3FE0,  // **#########* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF2 = 
+   0x0C00,  // ****##****** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x3000,  // **##******** ****
+   0x3F00,  // **######**** ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF3 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF4 = 
+   0x19C0,  // ***##**##*** ****
+   0x0000,  // ************ ****
+   0x3FC0,  // **########** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x0600,  // *****##***** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF5 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF6 = 
+   0x0600,  // *****##***** ****
+   0x0300,  // ******##**** ****
+   0x1FC0,  // ***#######** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF7 = 
+   0x0300,  // ******##**** ****
+   0x0600,  // *****##***** ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x3060,  // **##*****##* ****
+   0x1FC0,  // ***#######** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF8 = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x3DC0,  // **####*###** ****
+   0x0660,  // *****##**##* ****
+   0x3FE0,  // **#########* ****
+   0x6600,  // *##**##***** ****
+   0x3FC0,  // **########** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xF9 = 
+   0x0000,  // ************ ****
+   0x0FE0,  // ****#######* ****
+   0x1B00,  // ***##*##**** ****
+   0x3300,  // **##**##**** ****
+   0x7FC0,  // *#########** ****
+   0x6300,  // *##***##**** ****
+   0x6300,  // *##***##**** ****
+   0x63E0,  // *##***#####* ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xFA = 
+   0x0000,  // ************ ****
+   0x0300,  // ******##**** ****
+   0x0FC0,  // ****######** ****
+   0x0180,  // *******##*** ****
+   0x1FC0,  // ***#######** ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x1F80,  // ***######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xFB = 
+   0x0000,  // ************ ****
+   0x3F80,  // **#######*** ****
+   0x30C0,  // **##****##** ****
+   0x3060,  // **##*****##* ****
+   0x7C60,  // *#####***##* ****
+   0x3060,  // **##*****##* ****
+   0x30C0,  // **##****##** ****
+   0x3F80,  // **#######*** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+  { // 0xFC = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0180,  // *******##*** ****
+   0x3FC0,  // **########** ****
+   0x6360,  // *##***##*##* ****
+   0x6660,  // *##**##**##* ****
+   0x6C60,  // *##*##***##* ****
+   0x3FC0,  // **########** ****
+   0x1800,  // ***##******* ****
+   0x0000   // ************ ****
+  },
+  { // 0xFD = 
+   0x0060,  // *********##* ****
+   0x3FC0,  // **########** ****
+   0x61E0,  // *##****####* ****
+   0x6360,  // *##***##*##* ****
+   0x6660,  // *##**##**##* ****
+   0x6C60,  // *##*##***##* ****
+   0x7860,  // *####****##* ****
+   0x3FC0,  // **########** ****
+   0x6000,  // *##********* ****
+   0x0000   // ************ ****
+  },
+  { // 0xFE = 
+   0x0000,  // ************ ****
+   0x3000,  // **##******** ****
+   0x3000,  // **##******** ****
+   0x3F80,  // **#######*** ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x30C0,  // **##****##** ****
+   0x3F80,  // **#######*** ****
+   0x3000,  // **##******** ****
+   0x3000   // **##******** ****
+  },
+  { // 0xFF = 
+   0x3C00,  // **####****** ****
+   0x1800,  // ***##******* ****
+   0x1F80,  // ***######*** ****
+   0x18C0,  // ***##***##** ****
+   0x18C0,  // ***##***##** ****
+   0x1F80,  // ***######*** ****
+   0x1800,  // ***##******* ****
+   0x3C00,  // **####****** ****
+   0x0000,  // ************ ****
+   0x0000   // ************ ****
+  },
+
+  { // 0x60a = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x61a = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x62a = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x63a = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x64a = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x65a = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x66a = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x67a = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x68a = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x69a = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x6Aa = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x6Ba = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x6Ca = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x6Da = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x6Ea = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+  { // 0x6Fa = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0   // ******###### ****
+  },
+
+  { // 0x70a = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x71a = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x72a = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x73a = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x74a = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x75a = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x76a = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x77a = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x78a = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x79a = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x7Aa = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x7Ba = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x7Ca = 
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0x0000,  // ************ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x7Da = 
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFC00,  // ######****** ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x7Ea = 
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0x03F0,  // ******###### ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0   // ############ ****
+  },
+  { // 0x7Fa = 
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+   0xFFF0,  // ############ ****
+  }
+};
+   
+
+
+int NationalOptionSubsetG0Default[13]=
+    {0x23,0x94,0x80,0   ,0   ,0   ,0x5e,0x5f,0   ,0   ,0   ,0   ,0   };
+
+int NationalOptionSubsetCZ_SK[13]=
+    {0x23,0   ,0   ,0   ,0   ,0   ,0xed,0   ,0xec,0xeb,0   ,0xef,0   };
+int NationalOptionSubsetEN[13]=
+    {0x83,0x24,0x80,0x8b,0x8c,0x8d,0x8e,0x23,0x81,0x82,0x88,0x89,0x8a};
+int NationalOptionSubsetEE[13]=
+    {0x23,0xc6,0   ,0x5b,0x5c,0   ,0x5d,0xd6,0   ,0x7b,0x7c,0   ,0x7d};
+int NationalOptionSubsetFR[13]=
+    {0xd3,0xd4,0xd0,0xdb,0xdc,0xc1,0xde,0x23,0xd1,0xd2,0xd8,0xd9,0xcc};
+int NationalOptionSubsetDE[13]=
+    {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e};
+int NationalOptionSubsetIT[13]=
+    {0x83,0x24,0xd3,0x60,0xcc,0x8d,0x8e,0x23,0xdd,0xc1,0xc8,0xc9,0xca};
+int NationalOptionSubsetLV_LT[13]=
+    {0x23,0x24,0   ,0   ,0   ,0   ,0   ,0   ,0   ,0   ,0   ,0   ,0   };
+int NationalOptionSubsetPL[13]=
+    {0x23,0   ,0   ,0   ,0   ,0   ,0   ,0xee,0   ,0   ,0   ,0   ,0   };
+int NationalOptionSubsetPT_ES[13]=
+    {0xcc,0x24,0xe0,0xeb,0xec,0xed,0xee,0xef,0xe1,0x7d,0xe8,0xc9,0xc2};
+int NationalOptionSubsetRO[13]=
+    {0x23,0x94,0   ,0   ,0   ,0   ,0   ,0   ,0   ,0xd2,0   ,0   ,0xde};
+int NationalOptionSubsetSR_HR_SL[13]=
+    {0x23,0   ,0   ,0   ,0   ,0xfb,0   ,0xdb,0   ,0   ,0   ,0   ,0   };
+int NationalOptionSubsetSV_FI[13]=
+    {0x23,0x94,0x90,0x5b,0x5c,0x9d,0x5d,0x5f,0x91,0x7b,0x7c,0x99,0x7d};
+int NationalOptionSubsetTR[13]=
+    {0   ,0   ,0   ,0   ,0x5c,0xd7,0x5d,0   ,0   ,0   ,0x7c,0xcc,0x7d};
+
+
+
+inline int NationalOptionSubset(int chr) {
+    switch (chr) {
+        case 0x23: return 0;
+        case 0x24: return 1;
+        case 0x40: return 2;
+        case 0x5b: return 3;
+        case 0x5c: return 4;
+        case 0x5d: return 5;
+        case 0x5e: return 6;
+        case 0x5f: return 7;
+        case 0x60: return 8;
+        case 0x7b: return 9;
+        case 0x7c: return 10;
+        case 0x7d: return 11;
+        case 0x7e: return 12;
+    }
+    return -1;      
+}   
+
+inline unsigned int LeftBits(unsigned int bits) {
+    // Scale bit positions 0xfc00 to 0xfff0 positions
+    unsigned int res=0;
+    if (bits&0x8000) res|=0xC000;
+    if (bits&0x4000) res|=0x3000;
+    if (bits&0x2000) res|=0x0C00;
+    if (bits&0x1000) res|=0x0300;
+    if (bits&0x0800) res|=0x00C0;
+    if (bits&0x0400) res|=0x0030;
+    return res;
+}
+inline unsigned int RightBits(unsigned int bits) {
+    // Scale bit positions 0x03f0 to 0xfff0 positions
+    unsigned int res=0;
+    if (bits&0x0200) res|=0xC000;
+    if (bits&0x0100) res|=0x3000;
+    if (bits&0x0080) res|=0x0C00;
+    if (bits&0x0040) res|=0x0300;
+    if (bits&0x0020) res|=0x00C0;
+    if (bits&0x0010) res|=0x0030;
+    return res;
+}
+
+
+
+unsigned int* GetFontChar(cTeletextChar c, unsigned int *buffer) {
+    // Get character bitmap for character/charset
+
+    enumCharsets font=c.GetCharset();
+    int chr=c.GetChar();
+    unsigned int *bitmap=NULL;
+    int i;
+    int NationalOption=NationalOptionSubset(chr);
+    
+    switch (font) {
+    case CHARSET_LATIN_G0:
+        if (NationalOption>=0) {
+            if (NationalOptionSubsetG0Default[NationalOption]>0)
+                bitmap=TXT_Font[NationalOptionSubsetG0Default[NationalOption]-0x20];
+        } else {
+            if (chr>=0x20 && chr<0x80) {
+                bitmap=TXT_Font[chr-0x20];
+            }
+        }
+        break;
+    case CHARSET_LATIN_G0_EN:
+        if (NationalOption>=0) {
+            if (NationalOptionSubsetEN[NationalOption]>0)
+                bitmap=TXT_Font[NationalOptionSubsetEN[NationalOption]-0x20];
+        } else {
+            if (chr>=0x20 && chr<0x80) {
+                bitmap=TXT_Font[chr-0x20];
+            }
+        }           
+        break;
+    case CHARSET_LATIN_G0_FR:
+        if (NationalOption>=0) {
+            if (NationalOptionSubsetFR[NationalOption]>0)
+                bitmap=TXT_Font[NationalOptionSubsetFR[NationalOption]-0x20];
+        } else {
+            if (chr>=0x20 && chr<0x80) {
+                bitmap=TXT_Font[chr-0x20];
+            }
+        }           
+        break;
+    case CHARSET_LATIN_G0_IT:
+        if (NationalOption>=0) {
+            if (NationalOptionSubsetIT[NationalOption]>0)
+                bitmap=TXT_Font[NationalOptionSubsetIT[NationalOption]-0x20];
+        } else {
+            if (chr>=0x20 && chr<0x80) {
+                bitmap=TXT_Font[chr-0x20];
+            }
+        }           
+        break;
+    case CHARSET_LATIN_G0_PT_ES:
+        if (NationalOption>=0) {
+            if (NationalOptionSubsetPT_ES[NationalOption]>0)
+                bitmap=TXT_Font[NationalOptionSubsetPT_ES[NationalOption]-0x20];
+        } else {
+            if (chr>=0x20 && chr<0x80) {
+                bitmap=TXT_Font[chr-0x20];
+            }
+        }           
+        break;
+    case CHARSET_LATIN_G0_SV_FI:
+        if (NationalOption>=0) {
+            if (NationalOptionSubsetSV_FI[NationalOption]>0)
+                bitmap=TXT_Font[NationalOptionSubsetSV_FI[NationalOption]-0x20];
+        } else {
+            if (chr>=0x20 && chr<0x80) {
+                bitmap=TXT_Font[chr-0x20];
+            }
+        }           
+        break;
+    case CHARSET_LATIN_G0_DE:
+        if (chr>=0x20 && chr<0x80) {
+            bitmap=TXT_Font[chr-0x20];
+        }
+        break;
+    case CHARSET_LATIN_G0_CZ_SK:
+    case CHARSET_LATIN_G0_EE:
+    case CHARSET_LATIN_G0_LV_LT:
+    case CHARSET_LATIN_G0_PL:
+    case CHARSET_LATIN_G0_RO:
+    case CHARSET_LATIN_G0_SR_HR_SL:
+    case CHARSET_LATIN_G0_TR:
+        // Partially supported latin charsets
+        if (chr>=0x20 && chr<0x80 && NationalOption<0) {
+            bitmap=TXT_Font[chr-0x20];
+        }
+        break;
+        
+    case CHARSET_LATIN_G2:
+    case CHARSET_CYRILLIC_G0_SR_HR:
+    case CHARSET_CYRILLIC_G0_RU_BG:
+    case CHARSET_CYRILLIC_G0_UK:
+    case CHARSET_CYRILLIC_G2:
+    case CHARSET_GREEK_G0:
+    case CHARSET_GREEK_G2:
+    case CHARSET_ARABIC_G0:
+    case CHARSET_ARABIC_G2:
+    case CHARSET_HEBREW_G0:
+        // totally unsupported
+        break;
+        
+    case CHARSET_GRAPHICS_G1:
+        if (chr>=0x20 && chr<0x40) {
+            bitmap=TXT_Font[chr-0x20+0x80];
+        } else if (chr>=0x60 && chr<0x80) {
+            bitmap=TXT_Font[chr-0x60+0xE0];
+        }
+        break;
+    case CHARSET_GRAPHICS_G1_SEP:
+        if (chr>=0x20 && chr<0x40) {
+            bitmap=TXT_Font[chr-0x20+0x80];
+        } else if (chr>=0x60 && chr<0x80) {
+            bitmap=TXT_Font[chr-0x60+0xE0];
+        }
+        if (bitmap) {
+            for (i=0;i<10;i++) buffer[i]=bitmap[i]&TXT_Mask[i];
+            bitmap=buffer;
+        }
+        break;
+        
+    case CHARSET_GRAPHICS_G3:
+    case CHARSET_INVALID:
+        // Totally unsupported
+        break;
+    }
+    
+    
+    
+    if (!buffer) {
+        printf("Warning: Undefined char: %x %x\n",font,chr);
+        return NULL;
+    }
+    
+    switch (c.GetDblHeight()) {
+    case dblh_Top:
+        // Scale top 5 lines to full height
+        buffer[8]=buffer[9]=bitmap[4];
+        buffer[6]=buffer[7]=bitmap[3];
+        buffer[4]=buffer[5]=bitmap[2];
+        buffer[2]=buffer[3]=bitmap[1];
+        buffer[1]=buffer[0]=bitmap[0];
+        bitmap=buffer;
+        break;
+    case dblh_Bottom:
+        // Scale bottom 5 lines to full height
+        buffer[0]=buffer[1]=bitmap[5];
+        buffer[2]=buffer[3]=bitmap[6];
+        buffer[4]=buffer[5]=bitmap[7];
+        buffer[6]=buffer[7]=bitmap[8];
+        buffer[8]=buffer[9]=bitmap[9];
+        bitmap=buffer;
+    default:;
+    }
+
+    switch (c.GetDblWidth()) {
+    case dblw_Left:
+        // Scale 6 left columns to full width
+        buffer[0]=LeftBits(bitmap[0]);
+        buffer[1]=LeftBits(bitmap[1]);
+        buffer[2]=LeftBits(bitmap[2]);
+        buffer[3]=LeftBits(bitmap[3]);
+        buffer[4]=LeftBits(bitmap[4]);
+        buffer[5]=LeftBits(bitmap[5]);
+        buffer[6]=LeftBits(bitmap[6]);
+        buffer[7]=LeftBits(bitmap[7]);
+        buffer[8]=LeftBits(bitmap[8]);
+        buffer[9]=LeftBits(bitmap[9]);
+        bitmap=buffer;
+        break;
+    case dblw_Right:
+        // Scale 6 right columns to full width
+        buffer[0]=RightBits(bitmap[0]);
+        buffer[1]=RightBits(bitmap[1]);
+        buffer[2]=RightBits(bitmap[2]);
+        buffer[3]=RightBits(bitmap[3]);
+        buffer[4]=RightBits(bitmap[4]);
+        buffer[5]=RightBits(bitmap[5]);
+        buffer[6]=RightBits(bitmap[6]);
+        buffer[7]=RightBits(bitmap[7]);
+        buffer[8]=RightBits(bitmap[8]);
+        buffer[9]=RightBits(bitmap[9]);
+        bitmap=buffer;
+    default:;
+    }
+    
+    return bitmap;      
+}
diff --git a/teletxt/txtfont.h b/teletxt/txtfont.h
new file mode 100644 (file)
index 0000000..220bab3
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __TXTFONT_H
+#define __TXTFONT_H
+
+#include "../teletextdecodervbiebu.h"
+
+unsigned int* GetFontChar(cTeletextChar c, unsigned int *buffer);
+// Get a character bitmap for character/charset
+// Also handle double width/height partial characters
+// buffer must be an unsigned int[10] buffer, that *may* be used
+// to store the character - a different pointer may be returned too.
+// returns NULL if undefined character
+
+
+#endif
diff --git a/tfeed.cc b/tfeed.cc
new file mode 100644 (file)
index 0000000..d876a5d
--- /dev/null
+++ b/tfeed.cc
@@ -0,0 +1,88 @@
+/*\r
+    Copyright 2008 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#include "tfeed.h"\r
+\r
+#include "log.h"\r
+#include "demuxer.h"\r
+#include "callback.h"\r
+\r
+TFeed::TFeed(Callback* tcb)\r
+: cb(*tcb)\r
+{\r
+  teletextEnabled = 1;\r
+}\r
+\r
+int TFeed::init()\r
+{\r
+  return 1;\r
+}\r
+\r
+int TFeed::shutdown()\r
+{\r
+  // FIXME\r
+  return 1;\r
+}\r
+\r
+void TFeed::disable()\r
+{\r
+  teletextEnabled = 0;\r
+}\r
+\r
+void TFeed::enable()\r
+{\r
+  teletextEnabled = 1;\r
+}\r
+\r
+int TFeed::start()\r
+{\r
+  teletextEnabled = 1;\r
+  return threadStart();\r
+}\r
+\r
+void TFeed::stop()\r
+{\r
+  threadCancel();\r
+}\r
+\r
+void TFeed::threadMethod()\r
+{\r
+  bool tlen;\r
+\r
+  while(1)\r
+  {\r
+    threadCheckExit();\r
+\r
+    \r
+    tlen = Demuxer::getInstance()->writeTeletext();\r
+\r
+    if (tlen)\r
+    {\r
+      cb.call(this);\r
+//        Log::getInstance()->log("Tfeed", Log::DEBUG, "written");\r
+    }\r
+    else\r
+    {\r
+      //MILLISLEEP(100);\r
+        MILLISLEEP(20); //Performance Issue Marten\r
+    }\r
+    \r
+  }\r
+}\r
diff --git a/tfeed.h b/tfeed.h
new file mode 100644 (file)
index 0000000..9206a64
--- /dev/null
+++ b/tfeed.h
@@ -0,0 +1,55 @@
+/*\r
+    Copyright 2008 Marten Richter\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+*/\r
+\r
+#ifndef TFEED_H\r
+#define TFEED_H\r
+\r
+#include <stdio.h>\r
+#include <time.h>\r
+\r
+#ifdef WIN32\r
+#include "threadwin.h"\r
+#else\r
+#include "threadp.h"\r
+#endif\r
+\r
+class Callback;\r
+\r
+class TFeed : public Thread_TYPE\r
+{\r
+  public:\r
+    TFeed(Callback* tcb);\r
+\r
+    int init();\r
+    int shutdown();\r
+\r
+    int start();\r
+    void stop();\r
+    void enable();\r
+    void disable();\r
+\r
+  private:\r
+    void threadMethod();\r
+    void threadPostStopCleanup() {};\r
+    int teletextEnabled;\r
+    Callback& cb;\r
+};\r
+\r
+#endif\r
index 3315d73f8497c0e24ab352c08cb779e0f91636be..6347adc2502ecb48e3d53c2c3013ad4315ff9756 100644 (file)
 #include "log.h"
 #include "channel.h"
 
+
+
 VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
-        bool* availableAc3AudioChannels, int currentAudioChannel, RecInfo* recInfo)
+        bool* availableAc3AudioChannels, int currentAudioChannel, bool *availableSubtitleChannels,int*ttxtpages,
+        int currentSubtitleChannel,int currentSubtitleType, RecInfo* recInfo)
 {
   Log::getInstance()->log("VAS", Log::DEBUG, "%i", currentAudioChannel);
 
+
   parent = tparent;
 
   liveMode = false;
+  subtitles =false;
+  editsubtitles = false;
+
+  int i;
+  if (availableSubtitleChannels != NULL) {
+      for (i = 0; i < PES_DVBSUBTITLE_MAXCHANNELS; i++) {
+          if (availableSubtitleChannels[i])
+          {
+              AudioSubtitleChannel* sc = new AudioSubtitleChannel();
+              sc->type = 0x10;//dvbsubtitle
+              sc->name = NULL;
+              sc->pestype = PES_DVBSUBTITLE_START+ i;
+              scl.push_back(sc);
+          }
+      }
+      for (i=0;i<10;i++) {
+          if (ttxtpages[i]>0) {
+              AudioSubtitleChannel* sc = new AudioSubtitleChannel();
+              int length=strlen(tr("TTxt:"))+1+1+3+1;
+              sc->type = 0x11;//Teletxt
+              sc->name = new char[length];
+              SNPRINTF(sc->name,length,"%s %3x",tr("TTxt:"),ttxtpages[i]);
+              sc->pestype = ttxtpages[i];
+              scl.push_back(sc);
+          }
+      }
+  }
+
+  if (scl.size()>0) {
+        AudioSubtitleChannel* sc = new AudioSubtitleChannel();
+        sc->type = 0xFF;//special
+        sc->name = new char[strlen(tr("No Subtitles"))+1];
+        strcpy(sc->name,tr("No Subtitles"));
+        sc->pestype = 0;
+        scl.insert(scl.begin(),sc);
+        subtitles=true;
+  }
+
+
+
+  if (subtitles) {
+      setSize(400, 120);
+  } else {
+      setSize(200, 120);
+  }
 
-  setSize(200, 120);
   createBuffer();
 
-  sl.setPosition(40, 30);
-  sl.setSize(area.w - 45, area.h - 30);
-  add(&sl);
+  asl.setPosition(40, 30);
+  asl.setSize(200 - 45, area.h - 30);
+  add(&asl);
+
+  if (subtitles) {
+      ssl.setPosition(200+40,30);
+      ssl.setSize(200 - 45, area.h - 30);
+      add(&ssl);
+  }
 
   // Load data from availableAudioChannels, currentAudioChannel and recInfo
 
-  int i;
 
   for (i = 0; i < PES_AUDIO_MAXCHANNELS; i++)
   {
     if (availableMpegAudioChannels[i])
     {
-      AudioChannel* ac = new AudioChannel();
+      AudioSubtitleChannel* ac = new AudioSubtitleChannel();
       ac->type = 0;
       ac->name = NULL;
       ac->pestype = PES_AUDIO_START + i;
@@ -69,7 +122,7 @@ VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
     {
       if (availableAc3AudioChannels[i])
       {
-        AudioChannel* ac = new AudioChannel();
+        AudioSubtitleChannel* ac = new AudioSubtitleChannel();
         ac->type = 1;//ac3
         ac->name = NULL;
         ac->pestype = PES_AUDIO_AC3_START + i;
@@ -78,15 +131,22 @@ VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
     }
   }
 
+
+
+      
+
+
   unsigned char numchan_recinfo = recInfo->numComponents;
   unsigned char numchan_siz = acl.size();
+  unsigned char numchan_subtitles_siz = scl.size();
   int mp_audcounter = 0;
   int ac3_counter = 0;
   int ac3_offset = 0;
+  int dvb_subcounter = 1;
 
   for (i = 0; i < numchan_siz; i++)
   {
-    AudioChannel* ac = acl[i];
+    AudioSubtitleChannel* ac = acl[i];
     if (ac)
     {
       if (ac->type==0)
@@ -102,26 +162,35 @@ VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
   int type_int;
 
   for (i = 0; i < numchan_recinfo; i++)
-  {
-    if (recInfo->streams[i] != 2) continue; //not an audio component
+  {   
+    
     type = recInfo->types[i];
     lang = recInfo->languages[i];
     description = recInfo->descriptions[i];
-    AudioChannel* ac = NULL;
+    AudioSubtitleChannel* ac = NULL;
     type_int = 0;
-
-    switch (type)
-    {
-      case 1: //mpaudio mono
-      case 3: //mpaudio stereo
-        if (mp_audcounter < numchan_siz) ac = acl[mp_audcounter];
-        type_int = 0;
-        break;
-      case 5: //ac3
-        if (ac3_counter + ac3_offset < numchan_siz) ac = acl[ac3_counter + ac3_offset];
-        type_int = 1;
-        break;
-    }
+    if (recInfo->streams[i] == 2) {
+        switch (type)
+        {
+        case 1: //mpaudio mono
+        case 3: //mpaudio stereo
+            if (mp_audcounter < numchan_siz) ac = acl[mp_audcounter];
+            type_int = 0;
+            break;
+        case 5: //ac3
+            if (ac3_counter + ac3_offset < numchan_siz) ac = acl[ac3_counter + ac3_offset];
+            type_int = 1;
+            break;
+        }
+    } else if (recInfo->streams[i] == 3){
+      /*  switch (type)
+        {
+        case 20:*/
+            if (dvb_subcounter < numchan_subtitles_siz) ac = scl[dvb_subcounter];
+            type_int=0x10;
+       /*     break;
+        };*/
+    } else continue; //neither audio nor subtitle
 
     if (ac)
     {
@@ -148,6 +217,9 @@ VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
       case 1: //ac3
         ac3_counter++;
         break;
+      case 0x10:
+          dvb_subcounter++;
+        break;
     }
   }
 
@@ -160,11 +232,11 @@ VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
   {
     for(i = 0; i < audioChannelListSize; i++)
     {
-      AudioChannel* ac = acl[i];
+      AudioSubtitleChannel* ac = acl[i];
 
       if (ac->name)
       {
-        sl.addOption(ac->name, (ULONG)ac, (ac->pestype == currentAudioChannel));
+        asl.addOption(ac->name, (ULONG)ac, (ac->pestype == currentAudioChannel));
       }
       else
       {
@@ -180,34 +252,114 @@ VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
         {
           SNPRINTF(tempString, 299, "unknown");
         }
-        sl.addOption(tempString, (ULONG)ac, (ac->pestype == currentAudioChannel));
+        asl.addOption(tempString, (ULONG)ac, (ac->pestype == currentAudioChannel));
       }
     }
   }
   else
   {
-    sl.addOption(tr("No audio channel data available"), 0, 1);
+    asl.addOption(tr("No audio channel data available"), 0, 1);
   }
+
+  int subtitlesChannelListSize = scl.size();
+
+  if (subtitles) {
+      ssl.setDarkSelOption(true);
+      for(i = 0; i < subtitlesChannelListSize; i++)
+      {
+          AudioSubtitleChannel* sc = scl[i];
+          bool selected=false;
+          if (sc->pestype == currentSubtitleChannel && sc->type ==currentSubtitleType) selected=true;
+
+          if (sc->name)
+          {
+              ssl.addOption(sc->name, (ULONG)sc, selected);
+          }
+          else
+          {
+              if (sc->type==0x10)
+              {
+                  SNPRINTF(tempString, 299, "%lu", (ULONG)(sc->pestype - PES_DVBSUBTITLE_START));
+              }
+              else
+              {
+                  SNPRINTF(tempString, 299, "unknown");
+              }
+              ssl.addOption(tempString, (ULONG)sc, selected);
+          }
+      }
+  }
+
 }
 
-VAudioSelector::VAudioSelector(void* tparent, Channel* channel, int currentAudioChannel)
+VAudioSelector::VAudioSelector(void* tparent, Channel* channel, int currentAudioChannel,int currentSubtitletype,int currentSubtitleChannel,int*ttxtpages)
 {
   parent = tparent;
 
   liveMode = true;
+  editsubtitles = false;
+  subtitles =false;
+  UINT i;
+  
+  for (i = 0; i < channel->numSPids; i++)
+  {
+      AudioSubtitleChannel* sc = new AudioSubtitleChannel();
+      sc->type = 0x10;
+      sc->name = new char[strlen(channel->spids[i].name) + 1];
+      strcpy(sc->name, channel->spids[i].name);
+      sc->pestype = channel->spids[i].pid;
+      scl.push_back(sc);  
+  }
+  if (ttxtpages) {
+     for (i=0;i<10;i++) {
+          if (ttxtpages[i]>0) {
+            AudioSubtitleChannel* sc = new AudioSubtitleChannel();
+            int length=strlen(tr("TTxt:"))+1+1+3+1;
+            sc->type = 0x11;//Teletxt
+            sc->name = new char[length];
+            SNPRINTF(sc->name,length,"%s %3x",tr("TTxt:"),ttxtpages[i]);
+            sc->pestype = ttxtpages[i];
+            scl.push_back(sc);
+          }
+     }
+  }
+  
+
+  if (scl.size()>0) {
+        AudioSubtitleChannel* sc = new AudioSubtitleChannel();
+        sc->type = 0xFF;//special
+        sc->name = new char[strlen(tr("No Subtitles"))+1];
+        strcpy(sc->name,tr("No Subtitles"));
+        sc->pestype = 0;
+        scl.insert(scl.begin(),sc);
+        subtitles=true;
+  }
+
+
 
-  setSize(200, 120);
+  if (subtitles) {
+      setSize(400, 120);
+  } else {
+      setSize(200, 120);
+  }
   createBuffer();
 
-  sl.setPosition(40, 30);
-  sl.setSize(area.w - 45, area.h - 30);
-  add(&sl);
+  
+  asl.setPosition(40, 30);
+  asl.setSize(200 - 45, area.h - 30);
+  add(&asl);
+
+  if (subtitles) {
+      ssl.setPosition(200+40,30);
+      ssl.setSize(200 - 45, area.h - 30);
+      add(&ssl);
+  }
 
   // Load data from availableAudioChannels, currentAudioChannel and recInfo
 
-  for (UINT i = 0; i < channel->numAPids; i++)
+  for (i = 0; i < channel->numAPids; i++)
   {
-    AudioChannel* ac = new AudioChannel();
+    AudioSubtitleChannel* ac = new AudioSubtitleChannel();
     ac->type = 0;
     ac->name = new char[strlen(channel->apids[i].name) + 1];
     strcpy(ac->name, channel->apids[i].name);
@@ -217,9 +369,9 @@ VAudioSelector::VAudioSelector(void* tparent, Channel* channel, int currentAudio
   
   if (Audio::getInstance()->supportsAc3())
   {
-    for (UINT i = 0; i < channel->numDPids; i++)
+    for (i = 0; i < channel->numDPids; i++)
     {
-      AudioChannel* ac = new AudioChannel();
+      AudioSubtitleChannel* ac = new AudioSubtitleChannel();
       ac->type = 1;
       ac->name = new char[strlen(channel->dpids[i].name) + 1];
       strcpy(ac->name, channel->dpids[i].name);
@@ -232,15 +384,28 @@ VAudioSelector::VAudioSelector(void* tparent, Channel* channel, int currentAudio
 
   if (audioChannelListSize)
   {
-    for(int i = 0; i < audioChannelListSize; i++)
+    for(int j = 0; j < audioChannelListSize; j++)
     {
-      AudioChannel* ac = acl[i];
-      sl.addOption(ac->name, (ULONG)ac, (ac->pestype == currentAudioChannel));
+      AudioSubtitleChannel* ac = acl[j];
+      asl.addOption(ac->name, (ULONG)ac, (ac->pestype == currentAudioChannel));
     }
   }
   else
   {
-    sl.addOption(tr("No audio channel data available"), 0, 1);
+    asl.addOption(tr("No audio channel data available"), 0, 1);
+  }
+ int subtitlesChannelListSize = scl.size();
+
+  if (subtitles) {
+      ssl.setDarkSelOption(true);
+      for(int j = 0; j < subtitlesChannelListSize; j++)
+      {
+          AudioSubtitleChannel* sc = scl[j];
+          bool selected=false;
+          if ((sc->type==currentSubtitletype) && (sc->pestype == currentSubtitleChannel)) selected=true;
+          ssl.addOption(sc->name, (ULONG)sc, selected);
+          
+      }
   }
 }
 
@@ -256,7 +421,19 @@ VAudioSelector::~VAudioSelector()
   }
   acl.clear();
 
-  sl.clear();
+  asl.clear();
+
+  int subtitleChannelListSize = scl.size();
+  for(int i = 0; i < subtitleChannelListSize; i++)
+  {
+    // FIXME memory leak - nobody is deleting audio channel name? // try:
+    delete[] scl[i]->name;
+    Log::getInstance()->log("VAudioSelector", Log::DEBUG, "Deleted char[] on close");
+    delete scl[i];
+  }
+  scl.clear();
+
+  ssl.clear();
 
   Message* m = new Message();
   m->from = this;
@@ -273,9 +450,16 @@ void VAudioSelector::draw()
   
   rectangle(0, 0, area.w, 30, Colour::TITLEBARBACKGROUND);
   drawText(tr("Audio"), 45, 5, Colour::LIGHTTEXT);
+  if (subtitles) {
+      drawText(tr("Subtitles"), 45+200, 5, Colour::LIGHTTEXT);
+      ssl.setBackgroundColour(backgroundColour);
+      ssl.draw();
+  }
+
+  asl.setBackgroundColour(backgroundColour);
+  asl.draw();
 
-  sl.setBackgroundColour(backgroundColour);
-  sl.draw();
+  
 }
 
 int VAudioSelector::handleCommand(int command)
@@ -291,37 +475,81 @@ int VAudioSelector::handleCommand(int command)
     case Remote::DF_UP:
     case Remote::UP:
     {
-      sl.up();
-      sl.draw();
-
-      BoxStack::getInstance()->update(this);
-
-      Message* m = new Message();
-      m->from = this;
-      m->to = parent;
-      m->message = Message::AUDIO_CHANGE_CHANNEL;
-      m->parameter = (((AudioChannel*)sl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioChannel*)sl.getCurrentOptionData())->type &0xFF)<<16 ;
-      Command::getInstance()->postMessageNoLock(m);
+        if (editsubtitles) {
+            ssl.up();
+            ssl.draw();
+            BoxStack::getInstance()->update(this);
+            Message* m = new Message();
+            m->from = this;
+            m->to = parent;
+            m->message = Message::SUBTITLE_CHANGE_CHANNEL;
+            m->parameter = (((AudioSubtitleChannel*)ssl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioSubtitleChannel*)ssl.getCurrentOptionData())->type &0xFF)<<16 ;
+            Command::getInstance()->postMessageNoLock(m);
+        } else {
+            asl.up();
+            asl.draw();
+            BoxStack::getInstance()->update(this);
+            Message* m = new Message();
+            m->from = this;
+            m->to = parent;
+            m->message = Message::AUDIO_CHANGE_CHANNEL;
+            m->parameter = (((AudioSubtitleChannel*)asl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioSubtitleChannel*)asl.getCurrentOptionData())->type &0xFF)<<16 ;
+            Command::getInstance()->postMessageNoLock(m);
+        }
 
       return 2;
     }
     case Remote::DF_DOWN:
     case Remote::DOWN:
     {
-      sl.down();
-      sl.draw();
-
-      BoxStack::getInstance()->update(this);
-
-      Message* m = new Message();
-      m->from = this;
-      m->to = parent;
-      m->message = Message::AUDIO_CHANGE_CHANNEL;
-      m->parameter = (((AudioChannel*)sl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioChannel*)sl.getCurrentOptionData())->type &0xFF)<<16 ;
-      Command::getInstance()->postMessageNoLock(m);
+        if (editsubtitles) {
+            ssl.down();
+            ssl.draw();
+            BoxStack::getInstance()->update(this);
+            Message* m = new Message();
+            m->from = this;
+            m->to = parent;
+            m->message = Message::SUBTITLE_CHANGE_CHANNEL;
+            m->parameter = (((AudioSubtitleChannel*)ssl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioSubtitleChannel*)ssl.getCurrentOptionData())->type &0xFF)<<16 ;
+            Command::getInstance()->postMessageNoLock(m);
+        } else {
+            asl.down();
+            asl.draw();
+            BoxStack::getInstance()->update(this);
+            Message* m = new Message();
+            m->from = this;
+            m->to = parent;
+            m->message = Message::AUDIO_CHANGE_CHANNEL;
+            m->parameter = (((AudioSubtitleChannel*)asl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioSubtitleChannel*)asl.getCurrentOptionData())->type &0xFF)<<16 ;
+            Command::getInstance()->postMessageNoLock(m);
+        }
 
       return 2;
     }
+    case Remote::LEFT:
+     {
+        if (editsubtitles && subtitles) {
+            ssl.setDarkSelOption(true);
+            asl.setDarkSelOption(false);
+            editsubtitles=false;
+            asl.draw();
+            ssl.draw();
+            BoxStack::getInstance()->update(this);
+        }
+        return 2;
+     }
+     case Remote::RIGHT:
+     {
+         if (!editsubtitles && subtitles) {
+             ssl.setDarkSelOption(false);
+             asl.setDarkSelOption(true);
+             editsubtitles=true;
+             asl.draw();
+             ssl.draw();
+             BoxStack::getInstance()->update(this);
+         }
+        return 2;
+     }
   }
 
   return 1;
@@ -331,26 +559,69 @@ void VAudioSelector::processMessage(Message* m)
 {
   if (m->message == Message::MOUSE_MOVE)
   {
-    UINT lastsel=sl.getCurrentOption();
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
-    {
-      sl.draw();
-      BoxStack::getInstance()->update(this);
-      if ((int)lastsel!=sl.getCurrentOption()) 
-      { 
-        Message* m2 = new Message();
-        m2->from = this;
-        m2->to = parent;
-        m2->message = Message::AUDIO_CHANGE_CHANNEL;
-        m2->parameter = (((AudioChannel*)sl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioChannel*)sl.getCurrentOptionData())->type &0xFF)<<16 ;
-        Command::getInstance()->postMessageNoLock(m2);
+    
+      UINT lastsel=asl.getCurrentOption();
+      
+      if (((m->parameter>>16)-getScreenX()) < 200 && asl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+      {
+          editsubtitles=false;
+          ssl.setDarkSelOption(true);
+          asl.setDarkSelOption(false);
+          asl.draw();
+          ssl.draw();
+          BoxStack::getInstance()->update(this);
+          if ((int)lastsel!=asl.getCurrentOption()) 
+          { 
+              Message* m2 = new Message();
+              m2->from = this;
+              m2->to = parent;
+              m2->message = Message::AUDIO_CHANGE_CHANNEL;
+              m2->parameter = (((AudioSubtitleChannel*)asl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioSubtitleChannel*)asl.getCurrentOptionData())->type &0xFF)<<16 ;
+              Command::getInstance()->postMessageNoLock(m2);
+          }
+          return;
+        
       }
-    }
+      lastsel=ssl.getCurrentOption();
+      
+      if (ssl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+      {
+         editsubtitles=true;
+         ssl.setDarkSelOption(false);
+         asl.setDarkSelOption(true);
+         asl.draw();
+         ssl.draw();
+         BoxStack::getInstance()->update(this);
+         if ((int)lastsel!=ssl.getCurrentOption()) 
+         { 
+              Message* m2 = new Message();
+              m2->from = this;
+              m2->to = parent;
+              m2->message = Message::SUBTITLE_CHANGE_CHANNEL;
+              m2->parameter = (((AudioSubtitleChannel*)ssl.getCurrentOptionData())->pestype &0xFFFF)|(((AudioSubtitleChannel*)ssl.getCurrentOptionData())->type &0xFF)<<16 ;
+              Command::getInstance()->postMessageNoLock(m2);
+          }
+         return;
+     } 
   }
   else if (m->message == Message::MOUSE_LBDOWN)
   {
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    if (asl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      editsubtitles=false;
+      ssl.setDarkSelOption(true);
+      asl.setDarkSelOption(false);
+      asl.draw();
+      ssl.draw();
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
+    }
+    else if (ssl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
     {
+      editsubtitles=true;
+      ssl.setDarkSelOption(false);
+      asl.setDarkSelOption(true);
+      asl.draw();
+      ssl.draw();
       BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
     }
     else
index 31db81c4e5974f5212bcc578f627b469affb26c7..09d8afc48c3cbe099af67d22dca00e690be989a9 100644 (file)
@@ -36,8 +36,10 @@ class Channel;
 #define PES_AUDIO_MAXCHANNELS 0x20
 #define PES_AUDIO_AC3_MAXCHANNELS 0x08
 #define PES_AUDIO_AC3_START 0x80
+#define PES_DVBSUBTITLE_MAXCHANNELS 0x08
+#define PES_DVBSUBTITLE_START 0x20
 
-class AudioChannel
+class AudioSubtitleChannel
 {
   public:
     int type;
@@ -45,15 +47,22 @@ class AudioChannel
     int pestype;
 };
 
-typedef vector<AudioChannel*> AudioChannelList;
+
+
+typedef vector<AudioSubtitleChannel*> AudioSubtitleChannelList;
 
 class VAudioSelector : public TBBoxx
 {
   public:
     VAudioSelector(void* parent, bool* availableMpegAudioChannels,                    // Recording mode
-        bool* availableAc3AudioChannels, int currentAudioChannel, RecInfo* recInfo);
+        bool* availableAc3AudioChannels, int currentAudioChannel,
+        bool *availableSubtitleChannels,
+        int*ttxtpages,
+        int currentSubtitleChannel,int currentSubtitleType,
+        RecInfo* recInfo);
 
-    VAudioSelector(void* tparent, Channel* channel, int currentAudioChannel);         // Live mode
+    VAudioSelector(void* tparent, Channel* channel, int currentAudioChannel,
+        int currentSubtitleChannel,int currentSubtitletype,int*ttxtpages);         // Live mode
 
     VAudioSelector(void* parent, Channel* channel);
 
@@ -65,11 +74,15 @@ class VAudioSelector : public TBBoxx
 
   private:
     void* parent;
-    WSelectList sl;
+    WSelectList asl;
+    WSelectList ssl;
     
     bool liveMode;
+    bool subtitles;
+    bool editsubtitles;
 
-    AudioChannelList acl;
+    AudioSubtitleChannelList acl;
+    AudioSubtitleChannelList scl;
 };
 
 #endif
index d7bd9087ab35ab76e019cc430b33ce0f280643df..b351cf8f7c74d50954c791a6f4a2569dd8c6b095 100644 (file)
--- a/vfeed.cc
+++ b/vfeed.cc
@@ -75,7 +75,7 @@ void VFeed::threadMethod()
     else
     {
 //      Log::getInstance()->log("VFeed", Log::DEBUG, "No data delay");
-      MILLISLEEP(50);
+      MILLISLEEP(20);
     }
   }
 }
index 47b2d9a265b8145dbb05ea424b316232e1f1c937..cb73b9b9cf9ab81deab8c22ce3ca9a4ed4c0748a 100644 (file)
@@ -818,7 +818,7 @@ int VMediaList::handleCommand(int command)
         else
           playAudio(command==Remote::PLAY,true,true);
         break;
-        case MEDIA_TYPE_VIDEO:
+        case MEDIA_TYPE_VIDEO: {
         Log::getInstance()->log("VMediaList", Log::DEBUG, "play video file %s",
           media->getFileName());
         //OK - simply today
@@ -840,7 +840,7 @@ int VMediaList::handleCommand(int command)
         BoxStack::getInstance()->update(v);
         v->go(false);
         //play video
-        break;
+      }break;
         case MEDIA_TYPE_PICTURE:
         Log::getInstance()->log("VMediaList", Log::DEBUG, "show picture file %s",
          media->getFileName());
index 07c991511d28621b9b06e6b3109616f8dba1ff17..00a7c06ab5a418295051a03c7edb3af9dd33d63c 100644 (file)
@@ -539,7 +539,7 @@ int VMediaView::handleCommand(int command)
         showPicture(VMediaList::MV_NONE,slideshow,true);
         rt=2;
         break;
-      case Remote::MENU:
+      case Remote::MENU: {
         stopSlideshow(true);
         destroyPictureBanner();
         destroyInfo();
@@ -548,7 +548,8 @@ int VMediaView::handleCommand(int command)
         ct->draw();
         BoxStack::getInstance()->update(ct);
         rt=2;
-        break;
+       
+                         } break;
       case Remote::BACK:
       {
         setPictureMode(false);
diff --git a/vteletextview.cc b/vteletextview.cc
new file mode 100644 (file)
index 0000000..08274ee
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+    Copyright 2005-2008 Chris Tallon, Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP 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.
+
+    VOMP 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 VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+#include <math.h>
+#include "vteletextview.h"
+#include "video.h"
+#include "timers.h"
+#include "boxstack.h"
+#include "remote.h"
+#include "teletxt/txtfont.h"
+
+float interpol_table_fac1[16][22];
+float interpol_table_fac2[16][22];
+float interpol_table_fac3[16][22];
+float interpol_table_fac4[16][22];
+int interpol_lowbit[16];
+int interpol_upbit[16];
+int interpol_lowline[22];
+int interpol_upline[22];
+
+void initpol_tables(){
+    int charsizex;
+    int charsizey;
+    charsizex=16;
+    if (Video::getInstance()->getFormat() == Video::PAL)
+    { 
+        charsizey=22;
+    } else {
+        charsizey=18;
+    }
+    int ttcharsizex=12;
+    int ttcharsizey=10;
+    for (int py=0;py<charsizey;py++) {
+        float fposy=((float)(ttcharsizey))/((float)(charsizey))*((float)py);
+        float yweight=fposy-floor(fposy);
+        float yinvweight=1.-yweight;
+        interpol_upline[py]=min((unsigned int)ceil(fposy),9);
+        interpol_lowline[py]=max((unsigned int)floor(fposy),0);
+        for (int px=0;px<charsizex;px++) {
+            float fposx=((float)(ttcharsizex))/((float)(charsizex))*((float)px);
+            float xweight=fposx-floor(fposx);
+            float xinvweight=1.-xweight;
+            interpol_upbit[px]= (min((unsigned int)ceil(fposx),11));
+            interpol_lowbit[px]= (max((unsigned int)floor(fposx),0));
+
+            interpol_table_fac1[px][py]=xweight*yweight;
+            interpol_table_fac2[px][py]=xinvweight*yweight;
+            interpol_table_fac3[px][py]=xweight*yinvweight;
+            interpol_table_fac4[px][py]=xinvweight*yinvweight;
+
+        }
+    }
+}
+
+VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)
+{   
+    ttdecoder=TTdecoder;
+    pv=playerview;
+    subtitlemode=false;
+    initpol_tables();
+    
+    
+    if (Video::getInstance()->getFormat() == Video::PAL)
+    { 
+        //setSize(680, 550);
+        setSize(680,22); //Only first line
+        setPosition(40, 13);
+    }
+    else
+    {
+        setPosition(40, 15);
+        //setSize(680, 450);
+        setSize(680,18);//only first line
+    }
+    createBuffer();
+    keyindigit=1;
+    page=0x100;
+    
+}
+
+VTeletextView::~VTeletextView ()
+{
+    // Make sure the timer is deleted
+  pv->draw();
+  BoxStack::getInstance()->update(pv);
+  Timers::getInstance()->cancelTimer(this, 1);
+  ttdecoder->unRegisterTeletextView(this);
+    
+}
+
+void VTeletextView::draw(bool completedraw, bool onlyfirstline)
+{
+    Boxx::draw();
+    int x,y;
+    
+    for (y=0;y<25;y++) {
+        for (x=0;x<40;x++) {
+            if (ttdecoder->isDirty(x,y) || completedraw) {
+                cTeletextChar c=ttdecoder->getChar(x,y);
+                c.SetDirty(false);
+                //Skip Blinking and conceal
+                drawChar(x,y,c);
+                ttdecoder->setChar(x,y,c);
+            }
+        }
+        if (onlyfirstline) break;
+    }
+   
+    
+}
+
+Colour VTeletextView::enumTeletextColorToCoulour(enumTeletextColor ttcol)
+{
+    switch (ttcol) {
+        case ttcBlack:
+            return Colour(0,0,0);
+        case ttcRed:
+            return Colour(255,0,0);
+        case ttcGreen:
+            return Colour(0,255,0);
+        case ttcYellow:
+            return Colour(255,255,0);
+        case ttcBlue:
+            return Colour(0,0,255);
+        case ttcMagenta:
+            return Colour(255,0,255);
+        case ttcCyan:
+            return Colour(0,255,255);
+        case ttcWhite:
+            return Colour(255,255,255);
+        case ttcTransparent:
+            return Colour(0,0,0,0);
+        case ttcHalfRed:
+            return Colour(127,0,0);
+        case ttcHalfGreen:
+            return Colour(0,127,0);
+        case ttcHalfYellow:
+            return Colour(127,127,0);
+        case ttcHalfBlue:
+            return Colour(0,0,127);
+        case ttcHalfMagenta:
+            return Colour(127,0,127);
+        case ttcHalfCyan:
+            return Colour(0,127,127);
+        case ttcGrey:
+            return Colour(127,127,127);
+        default:
+            return Colour(0,0,0);
+    };
+}
+
+//Next function inspired by osdteletext plugin
+void VTeletextView::drawChar(int x, int y, cTeletextChar c)
+{
+    unsigned int buffer [10];
+    unsigned int * charmap=GetFontChar(c,buffer);
+    if (!charmap) { //invalid char
+        memset(&buffer,0,10);
+        charmap=buffer;
+    } 
+    enumTeletextColor ttforegcolour=c.GetFGColor();
+    enumTeletextColor ttbackgcolour=c.GetBGColor();
+    if (c.GetBoxedOut()) {
+        ttforegcolour=ttcTransparent;
+        ttbackgcolour=ttcTransparent;
+    }
+    int charsizex;
+    int charsizey;
+    charsizex=16;
+    bool firstline=false;
+    if (y==0) firstline=true;
+    if (Video::getInstance()->getFormat() == Video::PAL)
+    { 
+        charsizey=22;
+    } else {
+        charsizey=18;
+    }
+    int ttcharsizex=12;
+    int ttcharsizey=10;
+    int screenposx=charsizex*x; //12*40= 480 250
+    int screenposy=y*charsizey;
+    Boxx* drawtarget=this;
+    if (!firstline) {
+  
+        drawtarget=pv;
+        screenposy+=this->getScreenY();
+        screenposx+=this->getScreenX();
+
+    }
+
+    Colour fgcharcl=enumTeletextColorToCoulour(ttforegcolour);
+    Colour bgcharcl=enumTeletextColorToCoulour(ttbackgcolour);
+
+    drawtarget->startFastDraw();
+    for (int py=0;py<charsizey;py++) {
+        int upperbitline=charmap[interpol_upline[py]];
+        int lowerbitline=charmap[interpol_lowline[py]];
+        for (int px=0;px<charsizex;px++) {
+            int upperbit= interpol_upbit[px];
+            int lowerbit= interpol_lowbit[px];
+            Colour uuc=( upperbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;
+            Colour ulc=( upperbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;
+            Colour luc=( lowerbitline &(0x8000>>upperbit)) ? fgcharcl: bgcharcl;
+            Colour llc=( lowerbitline &(0x8000>>lowerbit)) ? fgcharcl: bgcharcl;
+            float fac1,fac2,fac3,fac4;
+            fac1=interpol_table_fac1[px][py];
+            fac2=interpol_table_fac2[px][py];
+            fac3=interpol_table_fac3[px][py];
+            fac4=interpol_table_fac4[px][py];
+         
+            Colour res(uuc.red*fac1+ulc.red*fac2+luc.red*fac3+llc.red*fac4,
+                uuc.green*fac1+ulc.green*fac2+luc.green*fac3+llc.green*fac4,
+                uuc.blue*fac1+ulc.blue*fac2+luc.blue*fac3+llc.blue*fac4,
+                uuc.alpha*fac1+ulc.alpha*fac2+luc.alpha*fac3+llc.alpha*fac4); //if this is too slow make a table
+            drawtarget->drawPixelAlpha(screenposx+px,screenposy+py,res, true);
+        }
+    }
+
+   
+    drawtarget->endFastDraw();
+
+
+}
+
+int VTeletextView::handleCommand(int command) {
+    if (subtitlemode) return 0; //Ok we are in  subtitle mode, we are a slave of the player
+    switch (command) {
+    case Remote::OK:
+        return 2;
+    case Remote::BACK:
+        return 4;
+     case Remote::ZERO:
+    case Remote::ONE:
+    case Remote::TWO:
+    case Remote::THREE:
+    case Remote::FOUR:
+    case Remote::FIVE:
+    case Remote::SIX:
+    case Remote::SEVEN:
+    case Remote::EIGHT:
+    case Remote::NINE:
+    {
+      // key in teletext page
+      doKey(command);
+      return 2;
+    }
+    };
+
+    return 0;
+    
+}
+
+void VTeletextView::doKey(int command)
+{
+    char pagenums[3];
+    if (keyindigit==1){
+        if (command==9) return; //not allowed
+        page=command<<8;
+        pagenums[0]=command+ 48;
+        pagenums[1]='-';
+        pagenums[2]='-';
+        keyindigit++;
+    } else if (keyindigit==2) {
+        page|=command<<4;
+        pagenums[0]=48+((page &0xF00)>>8);
+        pagenums[1]=command+ 48;
+        pagenums[2]='-';
+        keyindigit++;
+    } else if (keyindigit==3) {
+        page|=command;
+        pagenums[0]=48+((page &0xF00)>>8);
+        pagenums[1]=48+((page &0x0F0)>>4);
+        pagenums[2]=48+command;
+        keyindigit=1;
+        ttdecoder->setPage(page);
+    }
+    ttdecoder->setKeyinDigits(pagenums,true);
+    Region toupdate;
+    toupdate.w=16*40;
+    if (Video::getInstance()->getFormat() == Video::PAL) {
+        toupdate.h=22;
+        
+     } else {
+        toupdate.h=18;
+        
+      }
+     toupdate.x=0;
+     toupdate.y=0;
+            
+     draw(false,true);
+     BoxStack::getInstance()->update(this,&toupdate);
+
+}
+
+void VTeletextView::timercall(int clientReference)
+{
+    
+}
+
+void VTeletextView::processMessage(Message* m)
+{
+    if (m->message == Message::TELETEXTUPDATE)
+    {
+        draw(false,false);
+        BoxStack::getInstance()->update(this);
+        BoxStack::getInstance()->update(pv);
+
+    } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) 
+    {
+        Region toupdate;
+        toupdate.w=16*40;
+        if (Video::getInstance()->getFormat() == Video::PAL) {
+            toupdate.h=22;
+            
+        } else {
+            toupdate.h=18;
+            
+        }
+        toupdate.x=0;
+        toupdate.y=0;
+
+
+            
+        draw(false,true);
+        BoxStack::getInstance()->update(this,&toupdate);
+
+    }
+}
+
+
diff --git a/vteletextview.h b/vteletextview.h
new file mode 100644 (file)
index 0000000..d69a4a6
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+    Copyright 2005-2008 Chris Tallon, Marten Richter
+
+    This file is part of VOMP.
+
+    VOMP 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.
+
+    VOMP 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 VOMP; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef VTELETEXTVIEW_H
+#define VTELETEXTVIEW_H
+
+#include <stdio.h>
+
+#include "boxx.h"
+#include "timerreceiver.h"
+#include "teletextdecodervbiebu.h"
+
+class VTeletextView : public Boxx, public TimerReceiver
+{
+  public:
+    VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);
+    ~VTeletextView ();
+    void draw(bool completedraw, bool onlyfirstline);
+    void draw() {draw(true,false);};
+    void drawChar(int x, int y, cTeletextChar c);
+
+    Colour enumTeletextColorToCoulour(enumTeletextColor ttcol);
+
+    void processMessage(Message* m);
+
+    void setSubtitleMode(bool mode) {subtitlemode=mode;};
+    bool isInSubtitleMode() {return subtitlemode;};
+
+    int handleCommand(int command);
+    void timercall(int clientReference);
+   
+
+  private:
+      void doKey(int command);
+    
+
+  protected:
+      TeletextDecoderVBIEBU* ttdecoder;
+      int keyindigit;
+      int page;
+      bool subtitlemode;
+     Boxx* pv;
+    
+
+};
+
+#endif
index afa42927cfbf3d65178f1d319d68758034e45306..40838feab9c3ee70f7d0f44d4262893ea209ff0a 100644 (file)
@@ -40,6 +40,7 @@
 #include "vepg.h"
 #include "bitmap.h"
 #include "log.h"
+#include "vteletextview.h"
 
 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
 {
@@ -180,7 +181,7 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V
   textYellow.setBackgroundColour(osdBack);
   textYellow.setPosition(boxYellow.getX2(), 98);
   textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
-  textYellow.setText("");
+  textYellow.setText("Teletext");
   osd.add(&textYellow);  
     
   textBlue.setBackgroundColour(osdBack);
@@ -396,6 +397,7 @@ int VVideoLiveTV::handleCommand(int command)
     }
     case Remote::YELLOW:
     {
+      doTeletext(); //TODO: Add a selector for subtitles or teletext
       return 2;
     }
     case Remote::GUIDE:
@@ -573,10 +575,45 @@ void VVideoLiveTV::doKey(int command)
   delete[] keyingString;
 }
 
+void VVideoLiveTV::doTeletext(bool subtitlemode)
+{
+  bool exists=true;
+
+  // Cancel keying
+  if (keying)
+  {
+    keying = 0;
+    // and reset the display - this is a copy from setNowNextData
+    char formatChanNum[20];
+    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
+    osdChanNum.setText(formatChanNum);
+    osdChanName.setText((*chanList)[osdChannelIndex]->name);
+  }
+  if (osd.getVisible()) clearScreen();
+  // Draw the teletxt
+  VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+  if (vtxv==NULL) {
+       vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);
+      ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);
+      exists=false;
+  }
+  vtxv->setSubtitleMode(subtitlemode);
+  vtxv->draw();
+  draw();
+  
+  if (!exists) {
+      BoxStack::getInstance()->add(vtxv);
+  }
+  BoxStack::getInstance()->update(this);
+  BoxStack::getInstance()->update(vtxv); 
+}
+
 void VVideoLiveTV::doAudioSelector()
 {
   // If the osd is already visisble there might be a timer for it
   Timers::getInstance()->cancelTimer(this, 1);
+  //This causes a deadlock with the timertrhread itself is locked
+
 
   // Cancel keying
   if (keying)
@@ -588,9 +625,24 @@ void VVideoLiveTV::doAudioSelector()
     osdChanNum.setText(formatChanNum);
     osdChanName.setText((*chanList)[osdChannelIndex]->name);
   }
+  int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();
+  int subtitleType=0x10;
+  if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {
+      if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&
+          ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
+          ) {
+              subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();
+              subtitleType=0x11;
+          
+      } else {
+          subtitleType=0xFF; //turnedOff
+          subtitleChannel=0;
+      }
+  }
 
   // Draw the selector
-  vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel());
+  vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),
+      subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());
   Colour osdBack = Colour(0, 0, 0, 128);
   vas->setBackgroundColour(osdBack);
   vas->setPosition(0, osd.getScreenY() - vas->getHeight());
@@ -760,6 +812,7 @@ void VVideoLiveTV::timercall(int ref)
   {
     if (keying)
     {
+         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); 
       UINT newChannel = 0;
       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
       
@@ -769,9 +822,11 @@ void VVideoLiveTV::timercall(int ref)
       m->parameter = newChannel;
       m->tag = 1; // signal to call displayOSD();
       Command::getInstance()->postMessageFromOuterSpace(m);
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); 
     }
     else
     {
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); 
       // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
       if (preBuffering < 100)
       {
@@ -779,27 +834,39 @@ void VVideoLiveTV::timercall(int ref)
         Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
         return;
       }
-      
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); 
       osd.setVisible(false);
       okTriggeredOSD = false;
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); 
       draw();
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); 
       boxstack->update(this, osd.getRegion());
+
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); 
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); 
     }
   }
   else if (ref == 2)
   {
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2  start."); 
     setClock();
     if (osd.getVisible())
     {
       clock.draw();
       boxstack->update(this, osd.getRegion());
     }
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); 
   }
 }
 
 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
 {
   UINT newChannel = 0;
+  VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+  if (vtxt ) {
+       BoxStack::getInstance()->remove(vtxt);
+       
+  }
 
   if (changeType == INDEX)
   {
@@ -857,9 +924,11 @@ bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
   if (textUnavailable.getVisible())
   {
     textUnavailable.setVisible(false);
+    
+  }
+
     draw();
     BoxStack::getInstance()->update(this);
-  }
   
   return true;
 }
@@ -915,6 +984,44 @@ void VVideoLiveTV::processMessage(Message* m)
   {
     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
     player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);
+  } 
+  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
+  {
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
+      int type=((m->parameter & 0xFF0000)>>16);
+      switch (type) {
+      case 0x10: { //dvbsubtitle
+          if (streamType = VDR::VIDEO){
+              player->setSubtitleChannel((m->parameter & 0xFFFF));
+              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);
+              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+              if (vtxt && vtxt->isInSubtitleMode()) {
+                  BoxStack::getInstance()->remove(vtxt);
+              }
+          }
+                 } break;
+      case 0xFF: { //nosubtitles
+          if (streamType = VDR::VIDEO){
+              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
+              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+              if (vtxt && vtxt->isInSubtitleMode()) {
+                  BoxStack::getInstance()->remove(vtxt);
+              }  
+          }
+                 } break;
+      case 0x11: { //videotext
+          (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
+          doTeletext(true);
+          ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
+                 } break;
+      };
+      if (vas) {
+        BoxStack::getInstance()->update(vas);
+        //BoxStack::getInstance()->update(&osd); //eveil error
+      }
+      BoxStack::getInstance()->update(this, osd.getRegion());
+
+      
   }
   else if (m->message == Message::PLAYER_EVENT)
   {
index 8057d409982d320cf973a78792428cfcce046636..0ff6e84ddaa453ee168cd8b18bf54b29810a907f 100644 (file)
@@ -102,6 +102,7 @@ class VVideoLiveTV : public Boxx, public TimerReceiver, public OSDReceiver
     void doEPG();
     void doSummary();
     void doAudioSelector();
+    void doTeletext(bool subtitle=false);
     void stop();
     UINT upChannel(UINT index);
     UINT downChannel(UINT index);
index ac7fb21e74d1d0a4e0be30db8afc3174479f7775..daca8b17bcf910295af9f0526e7cb1c3de85f0df 100644 (file)
@@ -486,7 +486,8 @@ void VVideoMedia::doAudioSelector()
   RecInfo ri;
   ri.summary=new char[strlen(myMedia->getDisplayName())+1];
   strcpy(ri.summary,myMedia->getDisplayName());
-  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, &ri);
+  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);
   vas->setBackgroundColour(barBlue);
   vas->setPosition(0, barRegion.y - 120);
 
@@ -691,11 +692,11 @@ void VVideoMedia::doSummary()
   stlen+=strlen(tr("Time"))+50;
   char *pinfo=player->getInfo();
   stlen+=strlen(pinfo)+10;
-  char buf[stlen];
-  char tsbuf[stlen];
-  char tsbuf2[stlen];
-  char tbuf[Media::TIMEBUFLEN];
-  snprintf(buf,stlen,"%s\n" 
+  char *buf=new char [stlen];
+  char *tsbuf=new char [stlen];
+  char *tsbuf2=new char [stlen];
+  char *tbuf=new char[Media::TIMEBUFLEN];
+  SNPRINTF(buf,stlen,"%s\n" 
                    "%s: %llu Bytes\n"
                    "%s\n"
                    "%s: %s\n"
@@ -728,6 +729,10 @@ void VVideoMedia::doSummary()
   vsummary->draw();
 
   BoxStack::getInstance()->update(this);
+   delete [] buf;
+  delete []  tsbuf;
+  delete [] tsbuf2;
+  delete []  tbuf;
 }
 
 void VVideoMedia::removeSummary()
index 0204dc4b96ebb28754002081a04ff382110094f7..e5c1bc0b48e263504fbd32bc9644fea1a3d22bea 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "vvideorec.h"
+#include "vteletextview.h"
 
 #include "command.h"
 #include "osd.h"
@@ -398,6 +399,30 @@ int VVideoRec::handleCommand(int command)
   return 1;
 }
 
+void VVideoRec::doTeletext()
+{
+  
+  bool exists=true;
+
+  
+  // Draw the teletxt
+  VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();
+  if (vtxv==NULL) {
+       vtxv= new VTeletextView((player)->getTeletextDecoder(),this);
+      (player)->getTeletextDecoder()->registerTeletextView(vtxv);
+      exists=false;
+  }
+  vtxv->setSubtitleMode(true);
+  vtxv->draw();
+  draw();
+  
+  if (!exists) {
+      BoxStack::getInstance()->add(vtxv);
+  }
+  BoxStack::getInstance()->update(this);
+  BoxStack::getInstance()->update(vtxv); 
+}
+
 void VVideoRec::processMessage(Message* m)
 {
   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
@@ -522,6 +547,41 @@ void VVideoRec::processMessage(Message* m)
     Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
     player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16 );
   }
+  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
+  {
+      Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
+      int type=((m->parameter & 0xFF0000)>>16);
+      switch (type) {
+      case 0x10: { //dvbsubtitle
+          player->setSubtitleChannel((m->parameter & 0xFFFF));
+          player->turnSubtitlesOn(true);
+          VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
+          if (vtxt && vtxt->isInSubtitleMode()) {
+              BoxStack::getInstance()->remove(vtxt);
+          }
+                 } break;
+      case 0xFF: { //nosubtitles
+          
+           player->turnSubtitlesOn(false);
+           VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
+           if (vtxt && vtxt->isInSubtitleMode()) {
+              BoxStack::getInstance()->remove(vtxt);
+           }  
+          
+                 } break;
+      case 0x11: { //videotext
+          player->turnSubtitlesOn(false);
+          doTeletext();
+          ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
+                 } break;
+      };
+      if (vas) {
+        BoxStack::getInstance()->update(vas);
+      }
+      BoxStack::getInstance()->update(this);
+
+      
+  } 
   else if (m->message == Message::CHILD_CLOSE)
   {
     if (m->from == vas)
@@ -570,14 +630,32 @@ void VVideoRec::toggleChopSides()
 void VVideoRec::doAudioSelector()
 {
   bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
-  bool* availableAc3AudioChannels = 0;
+  bool* availableAc3AudioChannels = NULL;
+  bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();
+  int *availableTTxtpages = player->getTeletxtSubtitlePages();
   int currentAudioChannel = player->getCurrentAudioChannel();
   if (Audio::getInstance()->supportsAc3())
   {
       availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
   }
+  int subtitleChannel=player->getCurrentSubtitleChannel();
+  int subtitleType=0x10;
+  if (!(player)->isSubtitlesOn()) {
+      if ((player)->getTeletextDecoder()->getTeletxtView() &&
+          (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
+          ) {
+              subtitleChannel=(player)->getTeletextDecoder()->getPage();
+              subtitleType=0x11;
+          
+      } else {
+          subtitleType=0xFF; //turnedOff
+          subtitleChannel=0;
+      }
+  }
+
 
-  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, myRec->recInfo);
+  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,
+      subtitleChannel, subtitleType, myRec->recInfo);
   vas->setBackgroundColour(barBlue);
   vas->setPosition(0, barRegion.y - 120);
 
index 8c89b74bd0a0e63053768fe457de4be540861761..081c88b2ba7601c3df9da571861a9c0057cdddc6 100644 (file)
@@ -59,6 +59,8 @@ class VVideoRec : public Boxx, public TimerReceiver, public OSDReceiver
     void clearOSD();
     void clearOSDArea(UINT posX, UINT posY, UINT width, UINT height);
 
+    void doTeletext();
+
   private:
     BoxStack* boxstack;
     VDR* vdr;
index b3c2999d5c10adf25d5a927ef93526ac93df307f..bde3d5ac05659884318bdcf5a5e0ddfef32d8821 100644 (file)
--- a/wjpeg.cc
+++ b/wjpeg.cc
 #include <setjmp.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#ifndef WIN32
 #include <unistd.h>
+#else
+
+#endif
 
 
 #include "i18n.h"
@@ -103,11 +107,13 @@ ULONG WindowsResourceJpegReader::initRead(const char *filename)
     buffer=NULL;
     size=0;
     FreeResource(hres);
+ }
 
  ULONG WindowsResourceJpegReader::getSize(){
    return (ULONG)size;
 }
 #else
+
 #define LocalReader LocalJpegReader
 class LocalJpegReader: public JpegReader {
   public:
@@ -549,7 +555,7 @@ int WJpeg::init(char* tfileName)
     delete reader;
     reader=NULL;
     owningReader=false;
-    snprintf(errbuf,200,"unable to open %s",tfileName);
+    SNPRINTF(errbuf,200,"unable to open %s",tfileName);
     return 0;
   }
   return 1;
@@ -575,7 +581,7 @@ void WJpeg::draw()
     if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
   }
   else {
-    snprintf(errbuf,200,"jpeg reader not initialized");
+    SNPRINTF(errbuf,200,"jpeg reader not initialized");
   }
   if (! ok) {
     drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);
diff --git a/wjpeg.h b/wjpeg.h
index de3a08587c13ca997dd661f34c4d597b1255b0c4..154cfc9bbea9152b322bd5000bf5f0f03600fe42 100644 (file)
--- a/wjpeg.h
+++ b/wjpeg.h
@@ -176,7 +176,7 @@ class WJpeg : public Boxx
        if (xb < 0 || yb < 0 ) {
          return;
        }
-       sfc->drawPixel((UINT)xb,(UINT)yb,c);
+       sfc->drawPixel((UINT)xb,(UINT)yb,c,true);
     }
 
     /**
index baa3005d710b49a7872ba10c2695732cfef4de68..707932dd5952f4b008750efe9efad4737f1fd615 100644 (file)
@@ -31,6 +31,7 @@ WSelectList::WSelectList()
   noLoop = 0;
   gap = 1;
   showseloption = true;
+  darkseloption = false;
   backgroundColour = Colour::VIEWBACKGROUND;
 }
 
@@ -116,7 +117,7 @@ void WSelectList::draw()
 
     if (i == selectedOption && showseloption)
     {
-      rectangle(0, ypos, area.w, fontHeight, Colour::SELECTHIGHLIGHT);
+      rectangle(0, ypos, area.w, fontHeight, darkseloption ? Colour::SELECTDARKHIGHLIGHT: Colour::SELECTHIGHLIGHT);
       drawOptionLine(options[i].text, 5, ypos, area.w - 5, Colour::DARKTEXT);
     }
     else
index 88d65f0a886c2bc1392003a2fa6b8ad035e23841..03ba36105d9ee40208ebc77990e2f7791566dddf 100644 (file)
@@ -47,6 +47,7 @@ class WSelectList : public Boxx
 
     void setNoLoop();
     void setShowSelOption(bool set) { showseloption = set; };
+    void setDarkSelOption(bool set) { darkseloption = set; };
     int addOption(const char* text, ULONG data, int selected);
     void draw();
     void setBackgroundColour(const Colour& colour);
@@ -79,7 +80,7 @@ class WSelectList : public Boxx
     int columns[10];
     int numColumns;
     int noLoop;
-    bool showseloption;
+    bool showseloption, darkseloption;
     
     UINT gap;
     Colour backgroundColour;