Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 8570)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -13,6 +13,7 @@
 #include "jitterometer.h"
 #include "recordingprofile.h"
 #include "videooutbase.h"
+#include "teletextdecoder.h"
 #include "tv_play.h"
 
 extern "C" {
@@ -158,6 +159,7 @@
     char        *GetScreenGrab(int secondsin, int &buflen,
                                int &vw, int &vh, float &ar);
     LiveTVChain *GetTVChain(void)             { return livetvchain; }
+    TeletextDecoder *GetTeletextDecoder(void);
 
     // Start/Reset/Stop playing
     void StartPlaying(void);
@@ -473,6 +475,7 @@
     bool      osdHasSubtitles;
     long long osdSubtitlesExpireAt;
     MythDeque<AVSubtitle> nonDisplayedSubtitles;
+    TeletextDecoder *tt_decoder;
 
     // OSD stuff
     OSD      *osd;
Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 8570)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -117,6 +117,7 @@
       wtxt(0), rtxt(0), text_size(0), ccline(""), cccol(0), ccrow(0),
       // Support for captions, teletext, etc. decoded by libav
       osdHasSubtitles(false),       osdSubtitlesExpireAt(-1),
+      tt_decoder(NULL),
       // OSD stuff
       osd(NULL),                    timedisplay(NULL),
       dialogname(""),               dialogtype(0),
@@ -213,6 +214,9 @@
             delete [] txtbuffers[i].buffer;
     }
 
+    if (tt_decoder)
+        delete tt_decoder;
+
     SetDecoder(NULL);
 
     if (FiltMan)
@@ -228,6 +232,13 @@
         delete videoOutput;
 }
 
+TeletextDecoder *NuppelVideoPlayer::GetTeletextDecoder(void)
+{
+    if (!tt_decoder)
+        tt_decoder = new TeletextDecoder();
+    return tt_decoder;
+}
+
 void NuppelVideoPlayer::SetWatchingRecording(bool mode)
 {
     watchingrecording = mode;
Index: libs/libmythtv/vbilut.h
===================================================================
--- libs/libmythtv/vbilut.h	(revision 8570)
+++ libs/libmythtv/vbilut.h	(working copy)
@@ -17,4 +17,15 @@
 extern const short          hamm24err[];
 extern const int            hamm24cor[];
 
+enum vbimode
+{
+    VBI_IVTV,        /// < IVTV packet
+    VBI_DVB,         /// < DVB packet
+    VBI_DVB_SUBTITLE /// < DVB subtitle packet
+};
+
+int hamm8(const uint8_t *p, int *err);
+int hamm84(const uint8_t *p, int *err);
+int hamm16(const uint8_t *p, int *err);
+
 #endif // _VBILUT_H_
Index: libs/libmythtv/teletextdecoder.cpp
===================================================================
--- libs/libmythtv/teletextdecoder.cpp	(revision 0)
+++ libs/libmythtv/teletextdecoder.cpp	(revision 0)
@@ -0,0 +1,193 @@
+/* =============================================================
+ * File  : vbidecoder.cpp
+ * Author: Frank Muenchow <beebof@gmx.de>
+ *         Martin Barnasconi
+ * Date  : 2005-10-25
+ *
+ * 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, 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.
+ *
+ * ============================================================= */
+#include <cstring>
+
+#include <stdint.h>
+#include <ctype.h>
+
+extern "C" {
+#include <inttypes.h>
+#include "ivtv_myth.h"
+#include "vbitext/vt.h"
+}
+
+using namespace std;
+
+#include "osd.h"
+#include "teletextdecoder.h"
+#include "vbilut.h"
+#include "mythcontext.h"
+#include "osdtypeteletext.h"
+#include "ccdecoder.h"
+
+/******************************************************************/
+//Decoder section
+//
+
+TeletextDecoder::TeletextDecoder() :
+// private stuff
+    m_teletextviewer(NULL), m_decodertype(-1)
+{
+}
+
+TeletextDecoder::~TeletextDecoder()
+{
+}
+
+/** \fn TeletextDecoder::Decode(const uint8_t*, int)
+ *  \brief Decodes teletext data
+ *
+ *  \param buf Points to the teletext data
+ *  \param vbimode VBI-Mode (as defined in vbilut.h)
+ */
+void TeletextDecoder::Decode(const uint8_t *buf, int vbimode)
+{
+    int err = 0;
+    int latin1 = -1;
+    uint8_t magazine, packet, header;
+    int zahl1;
+    int pagenum, subpagenum;
+    int lang, flags;
+
+    if (m_teletextviewer == NULL)
+    {
+        VERBOSE(VB_VBI,QString("TeletextDecoder: No Teletext Viewer defined!"));
+        return;
+    }
+
+    m_decodertype = vbimode;
+
+    switch (vbimode)
+    {
+        case VBI_IVTV:
+            header = hamm16(buf, &err);
+
+            if (err & 0xf000)
+                return; // error in data header
+
+            magazine = header & 7;
+            packet = (header >> 3) & 0x1f;
+
+            buf += 2;
+            break;
+
+        case VBI_DVB:
+        case VBI_DVB_SUBTITLE:
+            zahl1 = hamm84(buf,&err) * 16 + hamm84(buf+1,&err); 
+
+            magazine = 0;
+            if (buf[0] & 0x40)
+                magazine += 1;
+            if (buf[0] & 0x10)
+                magazine += 2;
+            if (buf[0] & 0x04)
+                magazine += 4;
+
+            packet = 0;
+            if (buf[0] & 0x01)
+                packet += 1;
+            if (buf[1] & 0x40)
+                packet += 2;
+            if (buf[1] & 0x10)
+                packet += 4;
+            if (buf[1] & 0x04)
+                packet += 8;
+            if (buf[1] & 0x01)
+                packet += 16;
+
+            if (err == 1)
+                return;  // error in data header
+
+            buf += 2;
+            break;
+
+        default:
+            return; // error in vbimode
+    }
+
+    switch (packet)
+    {
+        case 0:  // Page Header
+            int b1, b2, b3, b4;
+            switch (vbimode)
+            {
+                case VBI_IVTV:
+                    b1 = hamm16(buf, &err);// page number
+                    b2 = hamm16(buf+2, &err);// subpage number + flags
+                    b3 = hamm16(buf+4, &err);// subpage number + flags
+                    b4 = hamm16(buf+6, &err);// language code + more flags
+                    if (err & 0xf000)
+                        return;
+                    
+                    break;
+
+                case VBI_DVB:
+                case VBI_DVB_SUBTITLE:
+                    b1 = hamm84(buf+1, &err)*16+hamm84(buf, &err);
+                    b2 = hamm84(buf+3, &err)*16+hamm84(buf+2, &err);
+                    b3 = hamm84(buf+5, &err)*16+hamm84(buf+4, &err);
+                    b4 = hamm84(buf+7, &err)*16+hamm84(buf+6, &err);
+                    if (err == 1)
+                        return;
+                    
+                    break;
+
+                default:
+                    return; // error in vbimode
+            }
+
+            VERBOSE(VB_VBI, QString("Page Header found: "
+                                    "Magazine %1, Page Number %2")
+                    .arg(magazine).arg(b1));
+            subpagenum= (b2 + b3 * 256) & 0x3f7f;
+            pagenum = (magazine?:8)*256 + b1;
+
+            lang = "\0\4\2\6\1\5\3\7"[b4 >> 5] + (latin1 ? 0 : 8);
+            flags = b4 & 0x1F;
+            flags |= b3 & 0xC0;
+            flags |= (b2 & 0x80) >> 2;
+            m_teletextviewer->AddPageHeader(pagenum,subpagenum,buf,vbimode,lang,flags);
+
+            break;
+
+        default: // Page Data
+            m_teletextviewer->AddTeletextData((magazine?:8), packet, buf, vbimode);
+            break;
+    }
+    return;
+}
+
+/** \fn TeletextDecoder::SetViewer(OSDTypeTeletext*)
+ *  \brief Sets the Teletext Viewer Class
+ */
+void TeletextDecoder::SetViewer(OSDTypeTeletext *view)
+{
+    m_teletextviewer = view;
+}
+
+/** \fn TeletextDecoder::GetDecoderType(void) const
+ *  \brief returns the actual decoder type (DVB,IVTV,DVB_SUBTITLE...)
+ *         At the moment, this is just for the decision in tv_play.cpp
+ *         if to use the new TeletextDecoder class or the old one
+ */
+int TeletextDecoder::GetDecoderType(void) const
+{
+    return m_decodertype;
+}
+
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 8570)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -265,6 +265,7 @@
       video_codec_id(kCodec_NONE),
       maxkeyframedist(-1), 
       ccd(new CCDecoder(this)),
+      ttd(NULL),
       // Audio
       audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]),
       allow_ac3_passthru(false),    allow_dts_passthru(false),
@@ -290,6 +291,7 @@
 #endif
 
     audioIn.sample_size = -32; // force SetupAudioStream to run once
+    ttd = GetNVP()->GetTeletextDecoder();
 }
 
 AvFormatDecoder::~AvFormatDecoder()
@@ -1719,7 +1721,7 @@
                 // SECAM lines  6-23 
                 // PAL   lines  6-22
                 // NTSC  lines 10-21 (rare)
-                //ttd->Decode(buf+1, VBI_IVTV);
+                ttd->Decode(buf+1, VBI_IVTV);
                 break;
             case VBI_TYPE_CC:
                 // PAL   line 22 (rare)
@@ -1756,7 +1758,8 @@
     const uint8_t *buf     = pkt->data;
     const uint8_t *buf_end = pkt->data + pkt->size;
 
-    while (buf < buf_end);
+
+    while (buf < buf_end)
     {
         if (*buf == 0x10)
             buf++; // skip
@@ -1766,18 +1769,17 @@
         if (*buf == 0x02)
         {
             buf += 3;
-            //ttd->Decode(buf+1, VBI_DVB);
+            ttd->Decode(buf+1, VBI_DVB);
         }
         else if (*buf == 0x03)
         {
             buf += 3;
-            //ttd->Decode(buf+1, VBI_DVB_SUBTITLE);
+            ttd->Decode(buf+1, VBI_DVB_SUBTITLE);
         }
         else
         {
             VERBOSE(VB_VBI, QString("VBI: Unknown descriptor: %1").arg(*buf));
         }
-
         buf += 43;
     }
 }
@@ -2331,10 +2333,9 @@
 
         if (len > 0 &&
             curstream->codec->codec_type == CODEC_TYPE_DATA &&
-            curstream->codec->codec_id   == CODEC_ID_MPEG2VBI)
+            curstream->codec->codec_id   == CODEC_ID_DVB_VBI)
         {
             ProcessDVBDataPacket(curstream, pkt);
-
             av_free_packet(pkt);
             continue;
         }
Index: libs/libmythtv/osdtypeteletext.cpp
===================================================================
--- libs/libmythtv/osdtypeteletext.cpp	(revision 0)
+++ libs/libmythtv/osdtypeteletext.cpp	(revision 0)
@@ -0,0 +1,1188 @@
+/* =============================================================
+* File  : osdtypeteletext.cpp
+* Author: Frank Muenchow <beebof@gmx.de>
+*         Martin Barnasconi
+* Date  : 2005-10-25
+*
+* 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, 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.
+*
+* ============================================================= */
+#include "osd.h"
+#include "osdsurface.h"
+#include "osdtypes.h"
+#include "osdtypeteletext.h"
+#include "ttfont.h"
+#include "vbilut.h"
+
+#include <qcolor.h>
+#include <qapplication.h>
+#include <iostream>
+#include <cmath>
+#include <qmutex.h>
+
+using namespace std;
+
+QColor m_color_black;
+QColor m_color_red;
+QColor m_color_green;
+QColor m_color_yellow;
+QColor m_color_blue;
+QColor m_color_magenta;
+QColor m_color_cyan;
+QColor m_color_white;
+
+/*****************************************************************************/
+OSDTypeTeletext::OSDTypeTeletext(const QString &name, QRect displayrect,
+                                TTFFont *font)
+    : OSDType(name)
+{
+    m_surface = NULL;
+
+    m_displayrect = displayrect;
+    m_font = font;
+
+    m_tt_colspace = m_displayrect.width()  / COLS;
+    m_tt_rowspace = m_displayrect.height() / ROWS;
+
+    m_color_black   = QColor(  0,  0,  0);
+    m_color_red     = QColor(255,  0,  0);
+    m_color_green   = QColor(  0,255,  0);
+    m_color_yellow  = QColor(255,255,  0);
+    m_color_blue    = QColor(  0,  0,255);
+    m_color_magenta = QColor(255,  0,255);
+    m_color_cyan    = QColor(  0,255,255);
+    m_color_white   = QColor(255,255,255);
+
+    Reset();
+
+    m_curpage = 0x100;
+    m_cursubpage = -1;
+    m_curpage_showheader = true;
+
+    m_pageinput[0] = '1';
+    m_pageinput[1] = '0';
+    m_pageinput[2] = '0';
+
+    m_displaying = false;
+
+    // fill Bitswap
+    for (int i = 0; i < 256; i++)
+    {
+        bitswap[i] = 0;
+        for (int bit = 0; bit < 8; bit++)
+            if (i & (1 << bit))
+                bitswap[i] |= (1 << (7-bit));
+    }
+}
+
+OSDTypeTeletext::OSDTypeTeletext(const OSDTypeTeletext &other)
+    : OSDType(other.m_name)
+{
+}
+
+OSDTypeTeletext::~OSDTypeTeletext()
+{
+}
+
+/** \fn OSDTypeTeletext::Reset()
+*  \brief Resets the teletext data cache
+*/
+void OSDTypeTeletext::Reset()
+{
+    for (int mag = 0; mag < 8; ++mag)
+    {
+        QMutexLocker lock(&m_magazines[mag].lock);
+
+        // clear all sub pages in page
+        std::map<int, TeletextPage>::iterator iter;
+        iter = m_magazines[mag].pages.begin();
+        while (iter != m_magazines[mag].pages.end())
+        {
+            TeletextPage *page = &iter->second;
+            page->subpages.clear();
+            ++iter;
+        }
+
+        // clear pages
+        m_magazines[mag].pages.clear();
+        m_magazines[mag].current_page = 0;
+        m_magazines[mag].current_subpage = 0;
+    }
+
+    m_curpage = 0x100;
+    m_cursubpage = -1;
+    m_curpage_showheader = true;
+}
+
+/** \fn OSDTypeTeletext::CharConversion(char, int)
+*  \brief converts the given character to the given language
+*/
+char OSDTypeTeletext::CharConversion(char ch, int lang)
+{
+    int c = 0;
+    for (int j = 0; j < 14; j++)
+    {
+        c = ch & 0x7F;
+        if (c == lang_chars[0][j])
+            ch = lang_chars[lang + 1][j];
+    }
+    return ch;
+}
+
+/** \fn OSDTypeTeletext::AddPageHeader(int, int, uint8_t*, int)
+*  \brief Adds a new page header 
+*         (page=0 if none)
+*/
+void OSDTypeTeletext::AddPageHeader(int page, int subpage, const uint8_t* buf, int vbimode, int lang, int flags)
+{
+    if (page < 256)
+        return;
+
+    int magazine = MAGAZINE(page);
+    int lastPage = m_magazines[magazine - 1].current_page;
+    int lastSubPage = m_magazines[magazine - 1].current_subpage;
+
+    // update the last fetched page if the magazine is the same 
+    // and the page no. is different
+    if (page != lastPage || subpage != lastSubPage)
+        PageUpdated(lastPage, lastSubPage);
+
+    m_fetchpage = page;
+    m_fetchsubpage = subpage;
+
+    TeletextSubPage *ttpage = FindSubPage(page, subpage);
+
+    if (ttpage == NULL)
+    {
+        ttpage = &m_magazines[magazine - 1].pages[page].subpages[subpage];
+        m_magazines[magazine - 1].pages[page].pagenum = page;
+        ttpage->subpagenum = subpage;
+
+        for (int i=0; i < 6; i++)
+            ttpage->floflink[i] = 0;
+    }
+
+    m_magazines[magazine - 1].current_page = page;
+    m_magazines[magazine - 1].current_subpage = subpage;
+
+    ttpage->lang = lang;
+    ttpage->flags = flags;
+    ttpage->flof = 0;
+
+    ttpage->subtitle = (vbimode == VBI_DVB_SUBTITLE);
+
+    for (int j = 0; j < 8; j++)
+        ttpage->data[0][j] = 32;
+
+    if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE)
+    {
+        for (int j = 8; j < 40; j++)
+            ttpage->data[0][j] = bitswap[buf[j]];
+    }
+    else 
+    {
+        memcpy(ttpage->data[0]+0, buf, 40);
+        memset(ttpage->data[0]+40, ' ', sizeof(ttpage->data)-40);
+    }
+    
+    if ( !(ttpage->flags & TP_INTERRUPTED_SEQ)) 
+        HeaderUpdated(ttpage->data[0],ttpage->lang);
+}
+
+/** \fn OSDTypeTeletext::AddTeletextData(int, int, uint8_t*)
+*  \brief Adds Teletext Data from TeletextDecoder
+*/
+void OSDTypeTeletext::AddTeletextData(int magazine, int row, 
+                                      const uint8_t* buf, int vbimode)
+{
+    int b1, b2, b3, err;
+
+    if (magazine < 1 || magazine > 8)
+        return;
+
+    int currentpage = m_magazines[magazine - 1].current_page;
+    int currentsubpage = m_magazines[magazine -1].current_subpage;
+    if (currentpage == 0)
+        return;
+
+    TeletextSubPage *ttpage = FindSubPage(currentpage, currentsubpage);
+
+    if (ttpage == NULL)
+        return;
+
+    switch (row)
+    {
+        case 1 ... 24: // Page Data
+            if (vbimode == VBI_DVB || vbimode == VBI_DVB_SUBTITLE)
+            {
+                for (int j = 0; j < 40; j++)
+                ttpage->data[row][j] = bitswap[buf[j]];
+            } 
+            else 
+            {
+                memcpy(ttpage->data[row], buf, 40);
+            }
+            break;
+        case 26:
+            /* XXX TODO: Level 1.5, 2.5, 3.5
+            *      Character location & override
+            * Level 2.5, 3.5
+            *      Modifying display attributes
+            * All levels
+            *      VCR Programming
+            * See 12.3
+            */
+            break;
+        case 27: // FLOF data (FastText)
+            switch (vbimode)
+            {
+                case VBI_IVTV:
+                    b1 = hamm8(buf, &err);
+                    b2 = hamm8(buf + 37, & err);
+                    if (err & 0xF00)
+                        return;
+                     break;
+                case VBI_DVB:
+                case VBI_DVB_SUBTITLE:
+                    b1 = hamm84(buf, &err);
+                    b2 = hamm84(buf + 37, &err);
+                    if (err == 1)
+                        return;
+                    break;
+                default:
+                    return;
+            }
+            if (b1 != 0 || not(b2 & 8))
+                return;
+
+            for (int i = 0; i < 6; ++i)
+            {
+                err = 0;
+                switch (vbimode)
+                {
+                    case VBI_IVTV:
+                        b1 = hamm16(buf+1+6*i, &err);
+                        b2 = hamm16(buf+3+6*i, &err);
+                        b3 = hamm16(buf+5+6*i, &err);
+                        if (err & 0xF000)
+                            return;
+                        break;
+                    case VBI_DVB:
+                    case VBI_DVB_SUBTITLE:
+                        b1 = hamm84(buf+2+6*i, &err) * 16 +
+                        hamm84(buf+1+6*i, &err);
+                        b2 = hamm84(buf+4+6*i, &err) * 16 +
+                        hamm84(buf+3+6*i, &err);
+                        b3 = hamm84(buf+6+6*i, &err) * 16 +
+                        hamm84(buf+5+6*i, &err);
+                        if (err == 1)
+                            return;
+                        break;
+                    default:
+                        return;
+                }
+
+                int x = (b2 >> 7) | ((b3 >> 5) & 0x06);
+                ttpage->floflink[i] = ((magazine ^ x) ?: 8) * 256 + b1;
+                ttpage->flof = 1;
+            }
+            break;
+
+        case 31: // private streams
+            break;
+
+        default: /// other packet codes...
+            break;
+    }
+}
+
+/** \fn OSDTypeTeletext::PageUpdated(int)
+*  \brief Updates the page, if given pagenumber is the same
+*         as the current shown page
+*/
+void OSDTypeTeletext::PageUpdated(int page, int subpage)
+{
+    if (!m_displaying)
+        return;
+
+    if (page != m_curpage)
+        return;
+
+    if (subpage != m_cursubpage && m_cursubpage != -1)
+        return;
+
+
+    if (m_surface != NULL)
+    {
+        m_surface->SetChanged(true);
+        m_surface->ClearUsed();
+        DrawPage();
+    }
+}
+
+/** \fn OSDTypeTeletext::HeaderUpdated(uint8_t*,int)
+*  \brief Updates the header (given in page with language lang)
+* 
+*  \param page Pointer to the header which should be displayed
+*  \param lang Language of the header
+*
+*/
+void OSDTypeTeletext::HeaderUpdated(uint8_t *page, int lang)
+{
+    if (!m_displaying)
+        return;
+
+    if (page == NULL)
+        return;
+
+    if (m_curpage_showheader == false)
+        return;
+
+    if (m_surface != NULL)
+        DrawHeader(page, lang);
+}
+
+/** \fn OSDTypeTeletext::FindPage(int, int)
+ *  \brief Finds the given page
+ *
+ *  \param page Page number
+ *  \param direction find page before or after the given page
+ *  \return TeletextPage (NULL if not found) 
+ */
+TeletextPage* OSDTypeTeletext::FindPage(int page, int direction)
+{
+    TeletextPage *res = NULL;
+    int mag = MAGAZINE(page);
+
+    if (mag > 8 || mag < 1)
+        return NULL;
+
+    QMutexLocker lock(&m_magazines[mag - 1].lock);
+
+    std::map<int, TeletextPage>::iterator pageIter;
+    pageIter = m_magazines[mag - 1].pages.find(page);
+    if (pageIter == m_magazines[mag - 1].pages.end())
+        return NULL;
+
+    res = &pageIter->second;
+    if (direction == -1)
+    {
+        --pageIter;
+        if (pageIter == m_magazines[mag - 1].pages.end())
+        {
+            std::map<int, TeletextPage>::reverse_iterator iter;
+            iter = m_magazines[mag - 1].pages.rbegin();
+            res = &iter->second;
+        }
+        else
+            res = &pageIter->second;
+    }
+
+    if (direction == 1)
+    {
+        ++pageIter;
+        if (pageIter == m_magazines[mag - 1].pages.end())
+        {
+            pageIter = m_magazines[mag - 1].pages.begin();
+            res = &pageIter->second;
+        }
+        else
+            res = &pageIter->second;
+    }
+
+    return res;
+}
+
+/** \fn OSDTypeTeletext::FindSubPage(int, int, int)
+*  \brief Finds the given page
+*
+*  \param page Page number
+*  \param subpage Subpage number (if set to -1, find the first subpage)
+*  \param direction find page before or after the given page (only if Subpage is not -1)
+*  \return TeletextSubPage (NULL if not found) 
+*/
+TeletextSubPage* OSDTypeTeletext::FindSubPage(int page, int subpage, int direction)
+{
+    TeletextSubPage *res = NULL;
+    int mag = MAGAZINE(page);
+
+    if (mag > 8 || mag < 1)
+        return NULL;
+
+    QMutexLocker lock(&m_magazines[mag - 1].lock);
+
+    if (subpage == -1)
+    {
+        // return the first subpage found
+        std::map<int, TeletextPage>::iterator pageIter;
+        pageIter = m_magazines[mag - 1].pages.find(page);
+        if (pageIter == m_magazines[mag - 1].pages.end())
+            return NULL;
+
+        TeletextPage *page = &pageIter->second;
+        std::map<int, TeletextSubPage>::iterator subpageIter;
+        subpageIter = page->subpages.begin();
+        if (subpageIter == page->subpages.end())
+            return NULL;
+
+        return &subpageIter->second;
+    }
+    else
+    {
+        // try to find the subpage given
+        std::map<int, TeletextPage>::iterator pageIter;
+        pageIter = m_magazines[mag - 1].pages.find(page);
+        if (pageIter == m_magazines[mag - 1].pages.end())
+            return NULL;
+
+        TeletextPage *page = &pageIter->second;
+        std::map<int, TeletextSubPage>::iterator subpageIter;
+        subpageIter = page->subpages.find(subpage);
+        if (subpageIter == page->subpages.end())
+            return NULL;
+
+        res = &subpageIter->second;
+        if (direction == -1)
+        {
+            --subpageIter;
+            if (subpageIter == page->subpages.end())
+            {
+                std::map<int, TeletextSubPage>::reverse_iterator iter;
+                iter = page->subpages.rbegin();
+                res = &iter->second;
+            }
+            else
+                res = &subpageIter->second;
+        }
+
+        if (direction == 1)
+        {
+            ++subpageIter;
+            if (subpageIter == page->subpages.end())
+            {
+                subpageIter = page->subpages.begin();
+                res = &subpageIter->second;
+            }
+            else
+                res = &subpageIter->second;
+        }
+    }
+
+    return res;
+}
+
+/** \fn OSDTypeTeletext::KeyPress(uint)
+*  \brief What to do if a key is pressed
+*
+*  \param key pressed key
+*  \sa TTKey
+*/
+void OSDTypeTeletext::KeyPress(uint key)
+{
+    int newPage = m_curpage;
+    int newSubPage = m_cursubpage;
+    bool numeric_input = false;
+
+    TeletextSubPage *curpage = FindSubPage(m_curpage, m_cursubpage);
+    TeletextPage *page;
+
+    switch (key)
+    {
+        case TTKey::k0 ... TTKey::k9:
+            numeric_input = true;
+            m_curpage_showheader = true;
+            if (m_pageinput[0] == ' ')
+                m_pageinput[0] = '0' + static_cast<int> (key);
+            else if (m_pageinput[1] == ' ')
+                m_pageinput[1] = '0' + static_cast<int> (key);
+            else if (m_pageinput[2] == ' ')
+            {
+                m_pageinput[2] = '0' + static_cast<int> (key);
+                newPage = ((m_pageinput[0] - '0') * 256) +
+                    ((m_pageinput[1] - '0') * 16) +
+                    (m_pageinput[2] - '0');
+                newSubPage = -1;
+            }
+            else
+            {
+                m_pageinput[0] = '0' + static_cast<int> (key);
+                m_pageinput[1] = ' ';
+                m_pageinput[2] = ' ';
+            }
+
+            break;
+
+        case TTKey::kNextPage:
+        {
+            TeletextPage *ttpage = FindPage(m_curpage, 1);
+            if (ttpage)
+                newPage = ttpage->pagenum;
+            newSubPage = -1;
+            m_curpage_showheader = true;
+            break;
+        } 
+
+        case TTKey::kPrevPage:
+        {
+            TeletextPage *ttpage = FindPage(m_curpage, -1);
+            if (ttpage)
+                newPage = ttpage->pagenum;
+            newSubPage = -1;
+            m_curpage_showheader = true;
+            break;
+        }
+
+        case TTKey::kNextSubPage:
+        {
+            TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, 1);
+            if (ttpage)
+                newSubPage = ttpage->subpagenum;
+            m_curpage_showheader = true;
+            break;
+        }
+
+        case TTKey::kPrevSubPage:
+        {
+            TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage, -1);
+            if (ttpage)
+                newSubPage = ttpage->subpagenum;
+            m_curpage_showheader = true;
+            break;
+        }
+
+        case TTKey::kHold:
+            break;
+
+        case TTKey::kTransparent:
+            m_transparent = !m_transparent;
+            PageUpdated(m_curpage, m_cursubpage);
+            break;
+
+        case TTKey::kRevealHidden:
+            m_revealHidden = !m_revealHidden;
+            PageUpdated(m_curpage, m_cursubpage);
+            break;
+
+        case TTKey::kFlofRed:
+        {
+            if (!curpage)
+                return;
+
+            if ((page = FindPage(curpage->floflink[0])) != NULL)
+            {
+                newPage = page->pagenum;
+                newSubPage = -1;
+                m_curpage_showheader = true;
+            }
+            break;
+        }
+
+        case TTKey::kFlofGreen:
+        {
+            if (!curpage)
+                return;
+
+            if ((page = FindPage(curpage->floflink[1])) != NULL)
+            {
+                newPage = page->pagenum;
+                newSubPage = -1;
+                m_curpage_showheader = true;
+            }
+            break;
+        }
+
+        case TTKey::kFlofYellow:
+        {
+            if (!curpage)
+                return;
+
+            if ((page = FindPage(curpage->floflink[2])) != NULL)
+            {
+                newPage = page->pagenum;
+                newSubPage = -1;
+                m_curpage_showheader = true;
+            }
+            break;
+        }
+
+        case TTKey::kFlofBlue:
+        {
+            if (!curpage)
+                return;
+
+            if ((page = FindPage(curpage->floflink[3])) != NULL)
+            {
+                newPage = page->pagenum;
+                newSubPage = -1;
+                m_curpage_showheader = true;
+            }
+            break;
+        }
+
+        case TTKey::kFlofWhite:
+        {
+            if (!curpage)
+                return;
+
+            if ((page = FindPage(curpage->floflink[4])) != NULL)
+            {
+                newPage = page->pagenum;
+                newSubPage = -1;
+                m_curpage_showheader = true;
+            }
+            break;
+        }
+    }
+
+    if (newPage < 0x100)
+        newPage = 0x100;
+    if (newPage > 0x899)
+        newPage = 0x899;
+
+    if (!numeric_input)
+    {
+        m_pageinput[0] = (newPage / 256) + '0';
+        m_pageinput[1] = ((newPage % 256) / 16) + '0';
+        m_pageinput[2] = (newPage % 16) + '0';
+    }
+
+    if (newPage != m_curpage || newSubPage != m_cursubpage)
+    {
+        m_curpage = newPage;
+        m_cursubpage = newSubPage;
+        m_revealHidden = false;
+        PageUpdated(m_curpage, m_cursubpage);
+    }
+}
+
+/** \fn OSDTypeTeletext::SetForegroundColor(int)
+*  \brief Set the font color to the given color.
+*
+*   NOTE: TTColor::TRANSPARENT does not do anything!
+*  \sa TTColor
+*/
+void OSDTypeTeletext::SetForegroundColor(int color)
+{
+    switch (color & ~TTColor::TRANSPARENT)
+    {
+        case TTColor::BLACK:   m_font->setColor(m_color_black);   break;
+        case TTColor::RED:     m_font->setColor(m_color_red);     break;
+        case TTColor::GREEN:   m_font->setColor(m_color_green);   break;
+        case TTColor::YELLOW:  m_font->setColor(m_color_yellow);  break;
+        case TTColor::BLUE:    m_font->setColor(m_color_blue);    break;
+        case TTColor::MAGENTA: m_font->setColor(m_color_magenta); break;
+        case TTColor::CYAN:    m_font->setColor(m_color_cyan);    break;
+        case TTColor::WHITE:   m_font->setColor(m_color_white);   break;
+    }
+
+    m_font->setShadow(0,0);
+    m_font->setOutline(0);
+}
+
+/** \fn OSDTypeTeletext:SetBackgroundColor(int)
+*  \brief Set the background color to the given color
+*
+*  \sa TTColor
+*/
+void OSDTypeTeletext::SetBackgroundColor(int ttcolor)
+{
+    QColor color;
+
+    switch (ttcolor & ~TTColor::TRANSPARENT)
+    {
+        case TTColor::BLACK:   color = m_color_black;   break;
+        case TTColor::RED:     color = m_color_red;     break;
+        case TTColor::GREEN:   color = m_color_green;   break;
+        case TTColor::YELLOW:  color = m_color_yellow;  break;
+        case TTColor::BLUE:    color = m_color_blue;    break;
+        case TTColor::MAGENTA: color = m_color_magenta; break;
+        case TTColor::CYAN:    color = m_color_cyan;    break;
+        case TTColor::WHITE:   color = m_color_white;   break;
+    }
+
+    int r = color.red();
+    int g = color.green();
+    int b = color.blue();
+
+    float y = (0.299*r) + (0.587*g) + (0.114*b);
+    float u = (0.564*(b - y)); // = -0.169R-0.331G+0.500B
+    float v = (0.713*(r - y)); // = 0.500R-0.419G-0.081B
+
+    m_bgcolor_y = (uint8_t)(y);
+    m_bgcolor_u = (uint8_t)(127 + u);
+    m_bgcolor_v = (uint8_t)(127 + v);
+    m_bgcolor_a = (ttcolor & TTColor::TRANSPARENT) ? 0x00 : 0xff;
+}
+
+/** \fn OSDTypeTeletext::DrawBackground(int, int)
+*  \brief draws background in the color set in setBackgroundColor
+*
+*  \param x X position (40 cols)
+*  \param y Y position (25 rows)
+*/
+void OSDTypeTeletext::DrawBackground(int x, int y)
+{
+    x *= m_tt_colspace;
+    x += m_displayrect.left();
+
+    y *= m_tt_rowspace;
+    y += m_displayrect.top();
+
+    DrawRect(x, y, m_tt_colspace, m_tt_rowspace);
+}
+
+/** \fn OSDTypeteletext::drawRect(int, int, int, int)
+*  \brief draws a Rectangle at position x and y (width dx, height dy)
+*         with the color set in setBackgroundColor
+*
+*  \param x X position at the screen
+*  \param y Y position at the screen
+*  \param dx width
+*  \param dy height
+*/
+void OSDTypeTeletext::DrawRect(int x, int y, int dx, int dy)
+{
+    QRect all(x, y, dx, dy);
+    m_surface->AddRect(all);
+
+    int luma_stride = m_surface->width;
+    int chroma_stride = m_surface->width >> 1;
+    int ye = y + dy;
+
+    unsigned char *buf_y = m_surface->y + (luma_stride * y) + x;
+    unsigned char *buf_u = m_surface->u + (chroma_stride * (y>>1)) + (x>>1);
+    unsigned char *buf_v = m_surface->v + (chroma_stride * (y>>1)) + (x>>1);
+    unsigned char *buf_a = m_surface->alpha + (luma_stride * y) + x;
+
+    for (; y<ye; ++y)
+    {
+        for (int i=0; i<dx; ++i)
+        {
+            buf_y[i] = m_bgcolor_y;
+            buf_a[i] = m_bgcolor_a;
+        }
+
+        if ((y & 1) == 0)
+        {
+            for (int i=0; i<dx; ++i)
+            {
+                buf_u[i>>1] = m_bgcolor_u;
+                buf_v[i>>1] = m_bgcolor_v;
+            }
+
+            buf_u += chroma_stride;
+            buf_v += chroma_stride;
+        }
+
+        buf_y += luma_stride;
+        buf_a += luma_stride;
+    }
+}
+
+/** \fn OSDTypeTeletext::DrawCharacter(int, int, QChar, int)
+*  \brief Draws a character at posistion x, y 
+*
+*  \param x X position (40 cols)
+*  \param y Y position (25 rows)
+*  \param ch Character
+*  \param doubleheight if different to 0, draw doubleheighted character
+*/
+void OSDTypeTeletext::DrawCharacter(int x, int y, QChar ch, int doubleheight)
+{
+    if (!m_font)
+        return;
+
+    QString line = ch;
+
+    x *= m_tt_colspace;
+    x += m_displayrect.left();
+
+    y *= m_tt_rowspace;
+    y += m_displayrect.top();
+
+    m_font->DrawString(m_surface, x, y, line,
+                    m_surface->width, m_surface->height,
+                    255, doubleheight!=0);
+}
+
+/** \fn OSDTypeTeletext::DrawMosaic(int, int, code, int)
+*  \brief Draws a mosaic as defined in ETSI EN 300 706
+*
+*  \param x X position (40 cols)
+*  \param y Y position (25 rows)
+*  \param code Code
+*  \param doubleheight if different to 0, draw doubleheighted mosaic)
+*/
+void OSDTypeTeletext::DrawMosaic(int x, int y, int code, int doubleheight)
+{
+    (void)x;
+    (void)y;
+    (void)code;
+
+    x *= m_tt_colspace;
+    x += m_displayrect.left();
+
+    y *= m_tt_rowspace;
+    y += m_displayrect.top();
+
+    int dx = (int)round(m_tt_colspace / 2)+1;
+    int dy = (int)round(m_tt_rowspace / 3)+1;
+
+    if (doubleheight != 0)
+    {
+        dx *= 2;
+        dy *= 2;
+    }
+
+    if (code & 0x10) DrawRect(x,      y + 2*dy, dx, dy);
+    if (code & 0x40) DrawRect(x + dx, y + 2*dy, dx, dy);
+    if (code & 0x01) DrawRect(x,      y,        dx, dy);
+    if (code & 0x02) DrawRect(x + dx, y,        dx, dy);
+    if (code & 0x04) DrawRect(x,      y + dy,   dx, dy);
+    if (code & 0x08) DrawRect(x + dx, y + dy,   dx, dy);
+}
+
+void OSDTypeTeletext::DrawLine(const uint8_t* page, uint row, int lang)
+{
+    bool mosaic;
+    bool conceal;
+    bool seperation;
+    bool flash;
+    bool doubleheight;
+    bool blink;
+    bool hold;
+    bool endbox;
+    bool startbox;
+
+    char last_ch = ' ';
+    char ch;
+
+    uint fgcolor = TTColor::WHITE;
+    uint bgcolor = TTColor::BLACK;
+    uint newfgcolor = TTColor::WHITE;
+    uint newbgcolor = TTColor::BLACK;
+
+    if (m_curpage_issubtitle || m_transparent)
+    {
+        bgcolor    = TTColor::TRANSPARENT;
+        newbgcolor = TTColor::TRANSPARENT;
+    }
+
+    SetForegroundColor(fgcolor);
+    SetBackgroundColor(bgcolor);
+
+    mosaic = false;
+    seperation = false;
+    conceal = false;
+    flash = false;
+    doubleheight = false;
+    blink = false;
+    hold = false;
+    endbox = false;
+    startbox = false;
+
+    if (row == 1)
+    {
+        for (uint x = 0; x < 8; x++)
+            DrawBackground(x, 1);
+    }
+
+    for (uint x = (row == 1 ? 8 : 0); x < COLS; ++x)
+    {
+        if (startbox)
+        {
+            bgcolor = bgcolor = TTColor::BLACK;
+            startbox = false;
+        }
+
+        if (endbox)
+        {
+            bgcolor = TTColor::TRANSPARENT;
+            endbox = false;
+        }
+
+        SetForegroundColor(fgcolor);
+        SetBackgroundColor(bgcolor);
+
+        ch = page[x] & 0x7F;
+        switch (ch)
+        {
+            case 0x00 ... 0x07: // alpha + foreground color
+                fgcolor = ch & 7;
+                mosaic = false;
+                conceal = false;
+                goto ctrl;
+            case 0x08: // flash
+                // XXX
+                goto ctrl;
+            case 0x09: // steady
+                flash = false;
+                goto ctrl;
+            case 0x0a: // end box
+                endbox = true;
+                goto ctrl;
+            case 0x0b: // start box
+                if (x < COLS - 1 && (page[x + 1] & 0x7F != 0x0b))
+                    startbox = true;
+                goto ctrl;
+            case 0x0c: // normal height
+                doubleheight = 0;
+                goto ctrl;
+            case 0x0d: // double height
+                doubleheight = row < ROWS-1;
+                goto ctrl;
+            case 0x10 ... 0x17: // graphics + foreground color
+                fgcolor = ch & 7;
+                mosaic = true;
+                conceal = false;
+                goto ctrl;
+            case 0x18: // conceal display
+                conceal = true;
+                goto ctrl;
+            case 0x19: // contiguous graphics
+                seperation = false;
+                goto ctrl;
+            case 0x1a: // separate graphics
+                seperation = true;
+                goto ctrl;
+            case 0x1c: // black background
+                bgcolor = TTColor::BLACK;
+                goto ctrl;
+            case 0x1d: // new background
+                bgcolor = fgcolor;
+                goto ctrl;
+            case 0x1e: // hold graphics
+                hold = true;
+                goto ctrl;
+            case 0x1f: // release graphics
+                hold = false;
+                goto ctrl;
+            case 0x0e: // SO (reserved, double width)
+            case 0x0f: // SI (reserved, double size)
+            case 0x1b: // ESC (reserved)
+                ch = ' ';
+                break;
+            ctrl:
+                ch = ' ';
+                if (hold && mosaic)
+                    ch = last_ch;
+            break;
+
+            case 0x80 ... 0x9f: // these aren't used
+                ch = ' '; // BAD_CHAR;
+                break;
+            default:
+                if (conceal && !m_revealHidden)
+                    ch = ' ';
+                break;
+        }
+
+        newfgcolor = fgcolor;
+        newbgcolor = bgcolor;
+
+        SetForegroundColor(newfgcolor);
+        SetBackgroundColor(newbgcolor);
+        if ((row != 0) || (x > 7))
+        {
+            if (m_transparent)
+                SetBackgroundColor(TTColor::TRANSPARENT);
+
+            DrawBackground(x, row);
+            if (doubleheight != 0)
+                    DrawBackground(x, row +1);
+
+            if ((mosaic) && (ch < 0x40 || ch > 0x5F))
+            {
+                SetBackgroundColor(newfgcolor);
+                DrawMosaic(x, row, ch, doubleheight);
+            }
+            else 
+            {
+                if (doubleheight != 0)
+                    DrawCharacter(x, row+1, CharConversion(ch, lang), doubleheight);
+                else
+                    DrawCharacter(x, row, CharConversion(ch, lang), doubleheight);
+            }
+        }
+    }
+}
+
+void OSDTypeTeletext::DrawHeader(const uint8_t* page, int lang)
+{
+    if (!m_displaying)
+        return;
+
+    DrawLine(page, 1, lang);
+    StatusUpdated();
+}
+
+void OSDTypeTeletext::DrawPage(void)
+{
+    if (!m_displaying)
+        return;
+
+    TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage);
+
+    if (ttpage == NULL)
+        return;
+
+    m_cursubpage = ttpage->subpagenum;
+
+    int a = 0;
+    if ((ttpage->subtitle) || (ttpage->flags & 
+            (TP_SUPPRESS_HEADER + TP_NEWSFLASH + TP_SUBTITLE)))
+    {
+        a = 1;
+        m_curpage_showheader = false;
+        m_curpage_issubtitle = true;
+    }
+    else
+    {
+        m_curpage_issubtitle = false;
+        m_curpage_showheader = true;
+        DrawHeader(ttpage->data[0], ttpage->lang);
+    }
+
+    for (int y = ROWS-a; y >= 2; y--)
+        DrawLine(ttpage->data[y-1], y, ttpage->lang);
+}
+
+void OSDTypeTeletext::Reinit(float wchange, float hchange)
+{
+    m_displayrect = QRect((int)(m_displayrect.x() * wchange),
+                        (int)(m_displayrect.y() * hchange),
+                        (int)(m_displayrect.width() * wchange),
+                        (int)(m_displayrect.height() * hchange));
+
+    m_tt_colspace = m_displayrect.width()  / COLS;
+    m_tt_rowspace = m_displayrect.height() / ROWS;
+}
+
+void OSDTypeTeletext::Draw(OSDSurface *surface, int fade, int maxfade,
+                        int xoff, int yoff)
+{
+    (void)surface;
+    (void)fade;
+    (void)maxfade;
+    (void)xoff;
+    (void)yoff;
+
+    m_surface = surface;
+    DrawPage();
+}
+
+void OSDTypeTeletext::StatusUpdated(void)
+{
+    SetForegroundColor(TTColor::WHITE);
+    SetBackgroundColor(TTColor::BLACK);
+
+    if (!m_transparent)
+        for (int i = 0; i < 40; ++i)
+            DrawBackground(i, 0);
+
+    DrawCharacter(1, 0, 'P', 0);
+    DrawCharacter(2, 0, m_pageinput[0], 0);
+    DrawCharacter(3, 0, m_pageinput[1], 0);
+    DrawCharacter(4, 0, m_pageinput[2], 0);
+
+    TeletextSubPage *ttpage = FindSubPage(m_curpage, m_cursubpage);
+
+    if (ttpage == NULL)
+    {
+        SetBackgroundColor(TTColor::BLACK);
+        SetForegroundColor(TTColor::WHITE);
+
+        if (!m_transparent)
+            for (int i = 7; i < 40; i++)
+                DrawBackground(i, 0);
+
+        char *str = "Page Not Available";
+        for (unsigned int i = 0; i < strlen(str); ++i)
+            DrawCharacter(i+10, 0, str[i], 0);
+
+        return;
+    }
+
+    // get list of available sub pages
+    QString str = "";
+    int count = 1, selected = 0;
+    TeletextPage *page = FindPage(m_curpage);
+    if (page)
+    {
+        std::map<int, TeletextSubPage>::iterator subpageIter;
+        subpageIter = page->subpages.begin();
+        while (subpageIter != page->subpages.end())
+        {
+            TeletextSubPage *subpage = &subpageIter->second;
+
+            if (subpage->subpagenum == m_cursubpage)
+            {
+                selected = count;
+                str += "*";
+            }
+            else
+                str += " ";
+
+            str += QString().sprintf("%02X", subpage->subpagenum);
+
+            ++subpageIter;
+            ++count;
+        }
+    }
+
+    if (str != "")
+    {
+        // if there are less than 9 subpages fill the empty slots with spaces
+        if (count < 10)
+        {
+            QString spaces;
+            spaces.fill(' ', 27 - str.length());
+            str = "  <" + str + spaces + " > ";
+        }
+        else
+        {
+            // try to centralize the selected sub page in the list
+            int startPos = selected - 5;
+            if (startPos < 0)
+                startPos = 0;
+            if (startPos + 9 >= count)
+                startPos = count - 10;
+
+            str = "  <" + str.mid(startPos * 3, 27) + " > ";
+        }
+
+        SetForegroundColor(TTColor::WHITE);
+        for (int x = 0; x < 11; x++)
+        {
+            if (m_transparent)
+                SetBackgroundColor(TTColor::TRANSPARENT);
+            else
+                SetBackgroundColor(TTColor::BLACK);
+
+            DrawBackground(x * 3 + 7, 0);
+
+            if (str[x * 3] == '*')
+            {
+                str[x * 3] = ' ';
+                SetBackgroundColor(TTColor::RED);
+            }
+
+            DrawBackground(x * 3 + 8, 0);
+            DrawBackground(x * 3 + 9, 0);
+
+            DrawCharacter(x * 3 + 7, 0, str[x * 3], 0);
+            DrawCharacter(x * 3 + 8, 0, str[x * 3 + 1], 0);
+            DrawCharacter(x * 3 + 9, 0, str[x * 3 + 2], 0);
+        }
+    }
+}
+
Index: libs/libmythtv/osdtypes.cpp
===================================================================
--- libs/libmythtv/osdtypes.cpp	(revision 8570)
+++ libs/libmythtv/osdtypes.cpp	(working copy)
@@ -11,6 +11,7 @@
 #include "ttfont.h"
 #include "osdsurface.h"
 #include "osdlistbtntype.h"
+#include "osdtypeteletext.h"
 
 #include "mythcontext.h"
 
@@ -101,6 +102,11 @@
             OSDTypeText *newtext = new OSDTypeText(*item);
             AddType(newtext);
         }
+        else if (OSDTypeTeletext *item = dynamic_cast<OSDTypeTeletext*>(type))
+        {
+            OSDTypeTeletext *newtt = new OSDTypeTeletext(*item);
+            AddType(newtt);
+        }
         else if (OSDTypePositionImage *item =
                   dynamic_cast<OSDTypePositionImage*>(type))
         {
@@ -180,6 +186,10 @@
         {
             item->Reinit(wchange, hchange);
         }
+        else if (OSDTypeTeletext *item = dynamic_cast<OSDTypeTeletext*>(type))
+        {
+            item->Reinit(wchange, hchange);
+        }
         else if (OSDTypePositionImage *item =
                  dynamic_cast<OSDTypePositionImage*>(type))
         {
@@ -657,7 +667,7 @@
   
 void OSDTypeText::DrawString(OSDSurface *surface, QRect rect, 
                              const QString &text, int fade, int maxfade, 
-                             int xoff, int yoff)
+                             int xoff, int yoff, bool doubl)
 {
     if (m_centered || m_right)
     {
@@ -694,7 +704,7 @@
     if (m_usingalt && m_altfont)
         font = m_altfont;
 
-    font->DrawString(surface, x, y, text, maxx, maxy, alphamod);
+    font->DrawString(surface, x, y, text, maxx, maxy, alphamod, doubl);
 } 
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Index: libs/libmythtv/tv_play.cpp
===================================================================
--- libs/libmythtv/tv_play.cpp	(revision 8570)
+++ libs/libmythtv/tv_play.cpp	(working copy)
@@ -33,6 +33,8 @@
 #include "config.h"
 #include "livetvchain.h"
 #include "playgroup.h"
+#include "osdtypeteletext.h"
+#include "teletextdecoder.h"
 
 #ifndef HAVE_ROUND
 #define round(x) ((int) ((x) + 0.5))
@@ -119,6 +121,12 @@
             "W");
     REG_KEY("TV Playback", "TOGGLECC", "Toggle Closed Captioning/Teletext",
             "T");
+    REG_KEY("TV Playback", "MENURED",        "Menu Red",        "F2");
+    REG_KEY("TV Playback", "MENUGREEN",      "Menu Green",      "F3");
+    REG_KEY("TV Playback", "MENUYELLOW",     "Menu Yellow",     "F4");
+    REG_KEY("TV Playback", "MENUBLUE",       "Menu Blue",       "F5");
+    REG_KEY("TV Playback", "MENUWHITE",      "Menu White",      "F6");
+    REG_KEY("TV Playback", "REVEAL",         "Teletext reveal hidden Text", "F7");
     REG_KEY("TV Playback", "DISPCC1", "Display CC1", "");
     REG_KEY("TV Playback", "DISPCC2", "Display CC2", "");
     REG_KEY("TV Playback", "DISPCC3", "Display CC3", "");
@@ -179,7 +187,7 @@
   Global:   Return, Enter, Space, Esc
 
   Global:          F1,
-  Playback: Ctrl-B,   F7,F8,F9,F10,F11
+  Playback: Ctrl-B,   F2,F3,F4,F5,F6,F7,F8,F9,F10,F11
  */
 }
 
@@ -212,7 +220,8 @@
       exitPlayer(false), paused(false), errored(false),
       stretchAdjustment(false),
       audiosyncAdjustment(false), audiosyncBaseline(LONG_LONG_MIN),
-      editmode(false), zoomMode(false), sigMonMode(false),
+      editmode(false),     zoomMode(false),
+      teletextmode(false), sigMonMode(false),
       update_osd_pos(false), endOfRecording(false), requestDelete(false),
       doSmartForward(false),
       queuedTranscode(false), getRecorderPlaybackInfo(false),
@@ -1084,6 +1093,18 @@
 
     if (nvp->IsPlaying())
     {
+        TeletextDecoder *tt_dec = nvp->GetTeletextDecoder();
+	
+	// This is needed because the OSDType does the decoding/caching of
+	// the teletext pages 
+	OSDSet *oset = GetOSD()->GetSet("teletext");
+	if (oset)
+	{
+	    OSDType *traw = oset->GetType("teletext");
+	    OSDTypeTeletext *tt_view = dynamic_cast<OSDTypeTeletext*>(traw);
+	    tt_dec->SetViewer(tt_view);
+	}
+
         activenvp = nvp;
         activerbuffer = prbuffer;
         StartOSD();
@@ -1753,6 +1774,52 @@
             return;
     }
 
+    //XXX ivtv/dvb teletext
+    if (teletextmode)
+    {
+        int passThru = 0;
+
+        for (unsigned int i = 0; i < actions.size() && !handled; i++)
+        {
+            QString action = actions[i];
+            handled = true;
+            if (action == "UP")
+                TeletextNavigate(-1);
+            else if (action == "DOWN")
+                TeletextNavigate(-2);
+            else if (action == "RIGHT")
+                TeletextNavigate(-3);
+            else if (action == "LEFT")
+                TeletextNavigate(-4);
+            else if (action == "TOGGLEASPECT")
+                TeletextNavigate(-5);
+            else if (action == "MENURED")
+                TeletextNavigate(-6);
+            else if (action == "MENUGREEN")
+                TeletextNavigate(-7);
+            else if (action == "MENUYELLOW")
+                TeletextNavigate(-8);
+            else if (action == "MENUBLUE")
+                TeletextNavigate(-9);
+            else if (action == "MENUWHITE")
+                TeletextNavigate(-10);
+            else if (action == "REVEAL")
+                TeletextNavigate(-11);
+            else if (action == "0" || action == "1" || action == "2" ||
+                     action == "3" || action == "4" || action == "5" ||
+                     action == "6" || action == "7" || action == "8" ||
+                     action == "9")
+                TeletextNavigate(action.toInt());
+            else if (action == "MENU" || action == "TOGGLECC" ||
+                     action == "ESCAPE")
+                TeletextStop();
+            else
+                handled = false;
+        }
+        if (!passThru)
+            return;
+    }
+
     if (zoomMode)
     {
         int passThru = 0;
@@ -2001,8 +2068,11 @@
         handled = true;
 
         if (action == "TOGGLECC" && !browsemode)
-        {
-            if (vbimode == VBIMode::NTSC_CC)
+	{
+            int dec_type = nvp->GetTeletextDecoder()->GetDecoderType();
+	    if (dec_type != -1)
+                TeletextStart();
+	    else if (vbimode == VBIMode::NTSC_CC)
                 nvp->ToggleCC(vbimode, 0);
             else if (ccInputMode)
             {
@@ -3233,6 +3303,14 @@
             aud->ToggleMute();
             muted = true;
         }
+        OSDSet *oset = GetOSD()->GetSet("teletext");
+        if (oset)
+        {
+            OSDType *traw = oset->GetType("teletext");
+            OSDTypeTeletext *tt_view = dynamic_cast<OSDTypeTeletext*>(traw);
+            if (tt_view)
+                tt_view->Reset();
+        }
     }
 
     if (nvp && (activenvp == nvp) && paused)
@@ -3461,6 +3539,14 @@
             aud->ToggleMute();
             muted = true;
         }
+        OSDSet *oset = GetOSD()->GetSet("teletext");
+        if (oset)
+        {
+            OSDType *traw = oset->GetType("teletext");
+            OSDTypeTeletext *tt_view = dynamic_cast<OSDTypeTeletext*>(traw);
+            if (tt_view)
+                tt_view->Reset();
+        }
     }
 
     if (nvp && (activenvp == nvp) && paused && GetOSD())
@@ -4772,6 +4858,121 @@
         GetOSD()->SetSettingsText(msg, 3);
 }
 
+//XXX new teletext
+void TV::TeletextStart(void)
+{
+    if (activenvp != nvp)
+        return;
+
+    if (paused || !GetOSD())
+        return;
+
+    TeletextDecoder *tt_dec = nvp->GetTeletextDecoder();
+    OSDSet *oset = GetOSD()->GetSet("teletext");
+    if (!oset)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "No teletext set available");
+        return;
+    }
+
+    OSDType *traw = oset->GetType("teletext");
+    OSDTypeTeletext *tt_view = dynamic_cast<OSDTypeTeletext*>(traw);
+    if (!tt_view)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "No teletext type available");
+        return;
+    }
+
+    tt_dec->SetViewer(tt_view);
+    tt_view->SetDisplaying(true);
+
+    teletextmode = true;
+
+    oset->Display();
+    GetOSD()->SetVisible(oset, 0);
+}
+
+void TV::TeletextNavigate(int page)
+{
+    if (!GetOSD())
+        return;
+
+    OSDSet *oset = GetOSD()->GetSet("teletext");
+    if (!oset)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "No teletext set available");
+        return;
+    }
+
+    OSDType *traw = oset->GetType("teletext");
+    OSDTypeTeletext *tt = dynamic_cast<OSDTypeTeletext*>(traw);
+    if (!tt)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "No teletext type available");
+        return;
+    }
+
+    switch (page)
+    {
+        case -1:
+            tt->KeyPress(TTKey::kNextPage);
+            break;
+        case -2:
+            tt->KeyPress(TTKey::kPrevPage);
+            break;
+        case -3:
+            tt->KeyPress(TTKey::kNextSubPage);
+            break;
+        case -4:
+            tt->KeyPress(TTKey::kPrevSubPage);
+            break;
+        case -5:
+            tt->KeyPress(TTKey::kTransparent);
+            break;
+        case -6:
+            tt->KeyPress(TTKey::kFlofRed);
+            break;
+        case -7:
+            tt->KeyPress(TTKey::kFlofGreen);
+            break;
+        case -8:
+            tt->KeyPress(TTKey::kFlofYellow);
+            break;
+        case -9:
+            tt->KeyPress(TTKey::kFlofBlue);
+            break;
+        case -10:
+            tt->KeyPress(TTKey::kFlofWhite);
+            break;
+        case -11:
+            tt->KeyPress(TTKey::kRevealHidden);
+            break;
+        case 0 ... 9:
+            tt->KeyPress(page);
+            break;
+    }
+}
+
+void TV::TeletextStop(void)
+{
+    if (!teletextmode || !GetOSD())
+        return;
+
+    OSDSet *oset = GetOSD()->GetSet("teletext");
+    if (oset)
+    {
+        OSDType *traw = oset->GetType("teletext");
+        OSDTypeTeletext *tt_view = dynamic_cast<OSDTypeTeletext*>(traw);
+        if (tt_view)
+           tt_view->SetDisplaying(false);
+    }	
+    GetOSD()->HideSet("teletext");
+
+    // nvp->GetTeletextDecoder()->SetViewer(NULL);
+
+    teletextmode = false;
+}
+
 void TV::BrowseChannel(const QString &chan)
 {
     if (!activerecorder->CheckChannel(chan))
@@ -4966,7 +5167,12 @@
     QString action = item->getAction();
 
     if (action == "TOGGLECC")
-        nvp->ToggleCC(vbimode, 0);
+    {
+        if (nvp->GetTeletextDecoder()->GetDecoderType() != -1)
+            TeletextStart();
+        else
+            nvp->ToggleCC(vbimode, 0);
+    }
     else if (action.left(6) == "DISPCC")
         nvp->ToggleCC(vbimode, action.right(1).toInt());
     else if (action.left(7) == "DISPTXT")
@@ -5694,6 +5900,9 @@
         activerbuffer->IgnoreLiveEOF(false);
     }
 
+    //if (nvp)
+    //    nvp->GetTeletextDecoder()->Reset();
+
     if (!nvp || (nvp && activenvp == nvp))
     {
         UpdateOSDProgInfo("program_info");
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 8570)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -188,7 +188,9 @@
     SOURCES += progfind.cpp             ttfont.cpp
 
     # Teletext stuff
+    HEADERS += teletextdecoder.h        osdtypeteletext.h
     HEADERS += vbilut.h
+    SOURCES += teletextdecoder.cpp      osdtypeteletext.cpp
     SOURCES += vbilut.cpp
 
     # C stuff
Index: libs/libmythtv/osdtypeteletext.h
===================================================================
--- libs/libmythtv/osdtypeteletext.h	(revision 0)
+++ libs/libmythtv/osdtypeteletext.h	(revision 0)
@@ -0,0 +1,187 @@
+#ifndef OSD_TYPE_TELETEXT_H_
+#define OSD_TYPE_TELETEXT_H_
+
+#include <vector>
+using namespace std;
+
+#include <qstring.h>
+#include <qrect.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+#include <qobject.h>
+#include <qcolor.h>
+#include <qmutex.h>
+
+#include "osdtypes.h"
+#include "teletextdecoder.h"
+
+class TTFFont;
+class OSDType;
+class OSDSurface;
+class TV;
+
+class TTColor
+{
+  public:
+    static const uint BLACK       = 0;
+    static const uint RED         = 1;
+    static const uint GREEN       = 2;
+    static const uint YELLOW      = 3;
+    static const uint BLUE        = 4;
+    static const uint MAGENTA     = 5;
+    static const uint CYAN        = 6;
+    static const uint WHITE       = 7;
+    static const uint TRANSPARENT = 8;
+};
+
+class TTKey
+{
+  public:
+    static const uint k0            = 0;
+    static const uint k1            = 1;
+    static const uint k2            = 2;
+    static const uint k3            = 3;
+    static const uint k4            = 4;
+    static const uint k5            = 5;
+    static const uint k6            = 6;
+    static const uint k7            = 7;
+    static const uint k8            = 8;
+    static const uint k9            = 9;
+    static const uint kNextPage     = 10;
+    static const uint kPrevPage     = 11;
+    static const uint kNextSubPage  = 12;
+    static const uint kPrevSubPage  = 13;
+    static const uint kHold         = 14;
+    static const uint kTransparent  = 15;
+    static const uint kFlofRed      = 16;
+    static const uint kFlofGreen    = 17;
+    static const uint kFlofYellow   = 18;
+    static const uint kFlofBlue     = 19;
+    static const uint kFlofWhite    = 20;
+    static const uint kRevealHidden = 21;
+};
+
+#define TP_SUPPRESS_HEADER  0x01
+#define TP_UPDATE_INDICATOR 0x02
+#define TP_INTERRUPTED_SEQ  0x04
+#define TP_INHIBIT_DISPLAY  0x08
+#define TP_MAGAZINE_SERIAL  0x10
+#define TP_ERASE_PAGE       0x20
+#define TP_NEWSFLASH        0x40
+#define TP_SUBTITLE         0x80
+
+class TeletextSubPage
+{
+  public:
+    int pagenum, subpagenum;  ///< the wanted page number
+    int lang;                 ///< language code
+    int flags;                ///< misc flags
+    uint8_t data[25][40];     ///< page data
+    int flof;                 ///< page has FastText links
+    int floflink[6];          ///< FastText links (FLOF)
+    bool subtitle;            ///< page is subtitle page
+};
+
+class TeletextPage
+{
+  public:
+    int pagenum;
+    int current_subpage;
+    std::map<int, TeletextSubPage> subpages;
+};
+
+#define MAGAZINE(page) page / 256
+
+class TeletextMagazine
+{
+  public:
+    QMutex lock;
+    int current_page;
+    int current_subpage;
+    std::map<int, TeletextPage> pages;
+};
+
+class OSDTypeTeletext : public OSDType 
+{
+    Q_OBJECT
+  public:
+    OSDTypeTeletext(const QString &name, QRect displayrect, TTFFont *font);
+    OSDTypeTeletext(const OSDTypeTeletext &other);
+    ~OSDTypeTeletext();
+
+    void Reset();
+
+    void Reinit(float wchange, float hchange);
+
+    void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+
+    void SetForegroundColor(int color);
+    void SetBackgroundColor(int color);
+
+    void DrawBackground(int x, int y);
+    void DrawRect(int x, int y, int dx, int dy);
+    void DrawCharacter(int x, int y, QChar ch, int doubleheight = 0);
+    void DrawMosaic(int x, int y, int code, int doubleheight);
+
+    void DrawLine(const uint8_t* page, uint row, int lang);
+    void DrawHeader(const uint8_t* page, int lang);
+    void DrawPage(void);
+
+    void NewsFlash(void) {};
+
+    void AddPageHeader(int page, int subpage, const uint8_t *buf, int vbimode, int lang, int flags);
+    void AddTeletextData(int magazine, int row, const uint8_t* buf, int vbimode);
+
+    void PageUpdated(int page, int subpage);
+    void HeaderUpdated(uint8_t* page, int lang);
+    void StatusUpdated(void);
+
+    void KeyPress(uint key);
+
+    void SetDisplaying(bool display) { m_displaying = display; };
+
+  private:
+    QMutex       m_lock;
+    QRect        m_displayrect;
+
+    TTFFont     *m_font;
+    OSDSurface  *m_surface;
+    OSDTypeBox  *m_box;
+
+    int          m_tt_colspace;
+    int          m_tt_rowspace;
+
+    uint8_t      m_bgcolor_y;
+    uint8_t      m_bgcolor_u;
+    uint8_t      m_bgcolor_v;
+    uint8_t      m_bgcolor_a;
+
+    // last fetched page
+    int m_fetchpage;
+    int m_fetchsubpage;
+
+    // currently displayed page:
+    int m_curpage;
+    int m_cursubpage;
+    int m_pageinput[3];
+    bool m_curpage_showheader;
+    bool m_curpage_issubtitle;
+
+    bool m_transparent;
+    bool m_revealHidden;
+
+    bool m_displaying;
+
+    TeletextMagazine m_magazines[8];
+    unsigned char    bitswap[256];
+
+    char CharConversion(char ch, int lang);
+    TeletextSubPage *FindSubPage(int page, int subpage, int direction = 0);
+    TeletextPage    *FindPage(int page, int direction = 0);
+
+    static const uint COLS = 40;
+    static const uint ROWS = 26;
+};
+
+#endif
+
Index: libs/libmythtv/osdtypes.h
===================================================================
--- libs/libmythtv/osdtypes.h	(revision 8570)
+++ libs/libmythtv/osdtypes.h	(working copy)
@@ -186,7 +186,8 @@
 
   private:
     void DrawString(OSDSurface *surface, QRect rect, const QString &text,
-                    int fade, int maxfade, int xoff, int yoff);
+                    int fade, int maxfade, int xoff, int yoff,
+                    bool double_size=false);
 
     QRect m_displaysize;
     QRect m_screensize;
Index: libs/libmythtv/tv_play.h
===================================================================
--- libs/libmythtv/tv_play.h	(revision 8570)
+++ libs/libmythtv/tv_play.h	(working copy)
@@ -257,6 +257,10 @@
     void DoSkipCommercials(int direction);
     void DoEditMode(void);
 
+    void TeletextStart(void);
+    void TeletextNavigate(int num);
+    void TeletextStop(void);
+    
     void DoQueueTranscode(void);  
 
     void SetAutoCommercialSkip(int skipMode = 0);
@@ -361,6 +365,7 @@
     long long audiosyncBaseline;
     bool editmode;          ///< Are we in video editing mode
     bool zoomMode;
+    bool teletextmode;   ///< Are we in teletext switching mode?
     bool sigMonMode;     ///< Are we in signal monitoring mode?
     bool update_osd_pos; ///< Redisplay osd?
     bool endOfRecording; ///< !nvp->IsPlaying() && StateIsPlaying(internalState)
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 8570)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -8,6 +8,8 @@
 #include "format.h"
 #include "decoderbase.h"
 #include "ccdecoder.h"
+#include "teletextdecoder.h"
+#include "vbilut.h"
 
 extern "C" {
 #include "frame.h"
@@ -232,6 +234,7 @@
 
     // Caption/Subtitle/Teletext decoders
     CCDecoder        *ccd;
+    TeletextDecoder  *ttd;
 
     // Audio
     short int        *audioSamples;
Index: libs/libmythtv/osdsurface.cpp
===================================================================
--- libs/libmythtv/osdsurface.cpp	(revision 8570)
+++ libs/libmythtv/osdsurface.cpp	(working copy)
@@ -86,11 +86,14 @@
     memset(u, 127, size / 4);
     memset(v, 127, size / 4);
     memset(alpha, 0, size);
+    usedRegionsLock.lock();
     usedRegions = QRegion();
+    usedRegionsLock.unlock();
 }
 
 void OSDSurface::ClearUsed(void)
 {
+    usedRegionsLock.lock();
     QMemArray<QRect> rects = usedRegions.rects();
     QMemArray<QRect>::Iterator it = rects.begin();
     QRect drawRect;
@@ -129,10 +132,12 @@
     }
 
     usedRegions = QRegion();
+    usedRegionsLock.unlock();
 }
 
 bool OSDSurface::IntersectsDrawn(QRect &newrect)
 {
+    QMutexLocker lock(&usedRegionsLock);
     QMemArray<QRect> rects = usedRegions.rects();
     QMemArray<QRect>::Iterator it = rects.begin();
     for (; it != rects.end(); ++it)
@@ -143,7 +148,9 @@
 
 void OSDSurface::AddRect(QRect &newrect)
 {
+    usedRegionsLock.lock();
     usedRegions = usedRegions.unite(newrect);
+    usedRegionsLock.unlock();
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -551,6 +558,7 @@
  */
 void OSDSurface::BlendToYV12(unsigned char *yuvptr) const
 {
+    usedRegionsLock.lock();
     const OSDSurface *surface = this;
     blendtoyv12_8_fun blender = blendtoyv12_8_init(surface);
 
@@ -649,6 +657,7 @@
             }
         }
     }
+    usedRegionsLock.unlock();
 }
 
 static void BlendToBlack(unsigned char *argbptr, uint width, uint outheight)
@@ -686,6 +695,7 @@
                              uint outheight, bool blend_to_black,
                              uint threshold) const
 {
+    usedRegionsLock.lock();
     const OSDSurface *surface = this;
     blendtoargb_8_fun blender = blendtoargb_8_init(surface);
     const unsigned char *cm = surface->cm;
@@ -756,6 +766,8 @@
     }
     if (blend_to_black)
         BlendToBlack(argbptr, stride>>2, outheight);
+
+    usedRegionsLock.unlock();
 }
 
 /** \fn OSDSurface::DitherToI44(unsigned char*,bool,uint,uint) const
@@ -772,6 +784,7 @@
 void OSDSurface::DitherToI44(unsigned char *outbuf, bool ifirst,
                              uint stride, uint outheight) const
 {
+    usedRegionsLock.lock();
     const OSDSurface *surface = this;
     int ashift = ifirst ? 0 : 4;
     int amask = ifirst ? 0x0f : 0xf0;
@@ -855,6 +868,7 @@
     }
 
     delete_dithertoia44_8_context(dcontext);
+    usedRegionsLock.unlock();
 }
 
 /** \fn OSDSurface::DitherToIA44(unsigned char*,uint,uint) const
Index: libs/libmythtv/vbilut.cpp
===================================================================
--- libs/libmythtv/vbilut.cpp	(revision 8570)
+++ libs/libmythtv/vbilut.cpp	(working copy)
@@ -325,3 +325,29 @@
     0x00000, 0x00800, 0x01000, 0x02000, 0x04000, 0x08000, 0x10000, 0x20000,
     0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
 };
+
+int hamm8(const uint8_t *p, int *err)
+{
+    int a =hammtab[p[0]];
+    *err += a;
+    return a & 15;
+}
+
+int hamm84(const uint8_t *p, int *err)
+{
+    int a = hamm84tab[p[0]];
+
+    if (a == 255)
+        *err = 1;
+
+    return a;
+}
+
+int hamm16(const uint8_t *p, int *err)
+{
+    int a = hammtab[p[0]];
+    int b = hammtab[p[1]];
+    *err += a;
+    *err += b;
+    return (a & 15) | (b & 15) * 16;
+}
Index: libs/libmythtv/ttfont.cpp
===================================================================
--- libs/libmythtv/ttfont.cpp	(revision 8570)
+++ libs/libmythtv/ttfont.cpp	(working copy)
@@ -157,7 +157,8 @@
    delete rmap;
 }
 
-Raster_Map *TTFFont::calc_size(int *width, int *height, const QString &text)
+Raster_Map *TTFFont::calc_size(int *width, int *height,
+                               const QString &text, bool double_size)
 {
    unsigned int i, pw, ph;
    Raster_Map *rtmp;
@@ -165,6 +166,9 @@
    pw = 0;
    ph = ((max_ascent) - max_descent) / 64;
 
+   if (double_size)
+       ph *= 2;
+
    for (i = 0; i < text.length(); i++)
    {
        unsigned short j = text[i].unicode();
@@ -200,12 +204,13 @@
 }
 
 void TTFFont::render_text(Raster_Map *rmap, Raster_Map *rchr,
-	                  const QString &text, int *xorblah, int *yor)
+                          const QString &text, int *xorblah, int *yor,
+                          bool double_size)
 {
    FT_F26Dot6 x, y, xmin, ymin, xmax, ymax;
    FT_BBox bbox;
    unsigned int i, ioff, iread;
-   char *off, *read, *_off, *_read;
+   char *off, *off2, *read, *_off, *_off2, *_read;
    int x_offset, y_offset;
    unsigned short j, previous;
    Raster_Map *rtmp;
@@ -326,20 +331,33 @@
 
        _read = (char *)rtmp->bitmap + iread;
        _off = (char *)rmap->bitmap + ioff;
-
+       _off2 = _off - rmap->cols;
+       
        for (y = ymin; y <= ymax; y++)
        {
            read = _read;
            off = _off;
+           off2 = _off2;
 
            for (x = xmin; x <= xmax; x++)
            {
-	       *off = *read;
+               *off = *read;
+               if (double_size)
+               {
+                   *off2 = *read;
+                   off2++;
+               }
                off++;
                read++;
            }
            _read -= rtmp->cols;
            _off -= rmap->cols;
+           if (double_size)
+           {
+               _off -= rmap->cols;
+               _off2 -= rmap->cols;
+               _off2 -= rmap->cols;
+           }
        }
        if (glyphs[j]->advance.x == 0)
            x_offset += 4;
@@ -413,7 +431,7 @@
 
 void TTFFont::DrawString(OSDSurface *surface, int x, int y, 
                          const QString &text, int maxx, int maxy, 
-                         int alphamod)
+                         int alphamod, bool double_size)
 {
    int                  width, height, w, h, inx, iny, clipx, clipy;
    Raster_Map          *rmap, *rtmp;
@@ -425,7 +443,7 @@
    inx = 0;
    iny = 0;
 
-   rtmp = calc_size(&w, &h, text);
+   rtmp = calc_size(&w, &h, text, double_size);
    if (w <= 0 || h <= 0)
    {
        destroy_font_raster(rtmp);
@@ -433,7 +451,7 @@
    }
    rmap = create_font_raster(w, h);
 
-   render_text(rmap, rtmp, text, &inx, &iny);
+   render_text(rmap, rtmp, text, &inx, &iny, double_size);
 
    is_pixmap = 1;
 
@@ -442,6 +460,9 @@
    width = maxx;
    height = maxy;
 
+   if (double_size)
+       height *= 2;
+
    clipx = 0;
    clipy = 0;
 
Index: libs/libmythtv/osd.cpp
===================================================================
--- libs/libmythtv/osd.cpp	(revision 8570)
+++ libs/libmythtv/osd.cpp	(working copy)
@@ -26,6 +26,7 @@
 #include "libmyth/oldsettings.h"
 #include "udpnotify.h"
 
+#include "osdtypeteletext.h"
 #include "osdlistbtntype.h"
 
 static float sq(float a) { return a*a; }
@@ -115,6 +116,8 @@
 
 void OSD::SetDefaults(void)
 {
+    OSDSet *container = NULL;
+// TODO begin -- deleted in teletext patch
     TTFFont *ccfont = GetFont("cc_font");
     if (!ccfont)
     {
@@ -130,8 +133,7 @@
     if (!ccfont)
         return;
 
-    OSDSet *container = GetSet("cc_page");
-    if (!container)
+    if (!GetSet("cc_page"))
     {
         QString name = "cc_page";
         container = new OSDSet(name, true,
@@ -157,10 +159,38 @@
                                           sub_dispw, sub_disph);
         container->AddType(ccpage);
     }
+// TODO end -- deleted in teletext patch
 
-    container = GetSet("menu");
-    if (!container)
+    if (!GetSet("teletext"))
     {
+        QString name = "teletext";
+        container = new OSDSet(name, true,
+                               osdBounds.width(), osdBounds.height(),
+                               wmult, hmult, frameint);
+        container->SetAllowFade(false);
+        container->SetWantsUpdates(true);
+        AddSet(container, name);
+        QRect area = QRect(20, 20, 620, 440);
+        normalizeRect(area);
+        // XXX TODO use special teletextfont
+        QString fontname = "teletextfont";
+        TTFFont *font = GetFont(fontname);
+        if (!font)
+        {
+            int fontsize = 440 / 26;
+            font = LoadFont(gContext->GetSetting("OSDCCFont"), fontsize);
+
+            if (font)
+                fontMap[fontname] = font;
+        }
+
+        OSDTypeTeletext *ttpage = new OSDTypeTeletext(name, area, font);
+  
+        container->AddType(ttpage);
+    }
+   
+    if (!GetSet("menu"))
+    {
         QString name = "menu";
         container = new OSDSet(name, true,
                                osdBounds.width(), osdBounds.height(),
Index: libs/libmythtv/teletextdecoder.h
===================================================================
--- libs/libmythtv/teletextdecoder.h	(revision 0)
+++ libs/libmythtv/teletextdecoder.h	(revision 0)
@@ -0,0 +1,43 @@
+#ifndef VBIDECODER_H_
+#define VBIDECODER_H_
+
+#include <stdint.h>
+
+#include <qwaitcondition.h>
+#include <qobject.h>
+#include <qmutex.h>
+
+class OSDTypeTeletext;
+class OSDType;
+class CCDecoder;
+
+class TeletextReader
+{
+  public:
+    virtual ~TeletextReader() { }
+    virtual void AddTextData(unsigned char *buf, int len,
+                             long long timecode, char type) = 0;
+};
+
+class TeletextDecoder : public QObject
+{
+    Q_OBJECT
+  public:
+    TeletextDecoder();
+    ~TeletextDecoder();
+
+    // Sets
+    void SetViewer(OSDTypeTeletext*);
+
+    // Gets
+    int GetDecoderType(void) const;
+
+    void Decode(const uint8_t *buf, int vbimode);
+
+  private:
+
+    OSDTypeTeletext        *m_teletextviewer;
+    int                     m_decodertype;
+};
+
+#endif
Index: libs/libmythtv/osdsurface.h
===================================================================
--- libs/libmythtv/osdsurface.h	(revision 8570)
+++ libs/libmythtv/osdsurface.h	(working copy)
@@ -2,6 +2,7 @@
 #define OSDSURFACE_H_
 
 #include <qregion.h>
+#include <qmutex.h>
 #include "blend.h"
 
 #define MAX_NEG_CROP 1024
@@ -61,7 +62,7 @@
     int size;
 
     QRegion usedRegions;
-
+    mutable QMutex usedRegionsLock;
 #ifdef MMX
     short int rec_lut[256];
 #else
Index: libs/libmythtv/ttfont.h
===================================================================
--- libs/libmythtv/ttfont.h	(revision 8570)
+++ libs/libmythtv/ttfont.h	(working copy)
@@ -42,7 +42,8 @@
      bool isValid(void) { return valid; }
 
      void DrawString(OSDSurface *surface, int x, int y, const QString &text,
-                     int maxx, int maxy, int alphamod = 255); 
+                     int maxx, int maxy, int alphamod = 255,
+                     bool double_size = false); 
      void CalcWidth(const QString &text, int *width_return);
 
      int SpaceWidth() { return spacewidth; }
@@ -58,9 +59,10 @@
      Raster_Map *duplicate_raster(FT_BitmapGlyph bmap);
      void clear_raster(Raster_Map *rmap);
      void destroy_font_raster(Raster_Map *rmap);
-     Raster_Map *calc_size(int *width, int *height, const QString &text);
+     Raster_Map *calc_size(int *width, int *height, const QString &text,
+                           bool double_size = false);
      void render_text(Raster_Map *rmap, Raster_Map *rchr, const QString &text, 
-                      int *xorblah, int *yor);
+                      int *xorblah, int *yor, bool double_size = false);
      void merge_text(OSDSurface *surface, Raster_Map *rmap, int offset_x, 
                      int offset_y, int xstart, int ystart, int width, 
                      int height, int alphamod, kTTF_Color k = kTTF_Normal);
Index: libs/libavformat/mpegts.c
===================================================================
--- libs/libavformat/mpegts.c	(revision 8570)
+++ libs/libavformat/mpegts.c	(working copy)
@@ -55,6 +55,7 @@
     int comp_page;
     int anc_page;
     int sub_id;
+    int txt_type;
 } dvb_caption_info_t;
 
 static int mpegts_parse_desc(dvb_caption_info_t *dvbci,
@@ -618,6 +619,8 @@
         if (dvbci.sub_id && (stream_type == STREAM_TYPE_PRIVATE_DATA))
             stream_type = STREAM_TYPE_SUBTITLE_DVB;
 
+        if (dvbci.txt_type && (stream_type == STREAM_TYPE_PRIVATE_DATA))
+            stream_type = STREAM_TYPE_VBI_DVB;
 #ifdef DEBUG_SI
         av_log(NULL, AV_LOG_DEBUG, "stream_type=%d pid=0x%x\n", stream_type, pid);
 #endif
@@ -784,7 +787,7 @@
         case STREAM_TYPE_AUDIO_AAC:
         case STREAM_TYPE_AUDIO_AC3:
         case STREAM_TYPE_AUDIO_DTS:
-//        case STREAM_TYPE_PRIVATE_DATA:
+        case STREAM_TYPE_VBI_DVB:
         case STREAM_TYPE_SUBTITLE_DVB:
             val = 1;
             break;
@@ -839,6 +842,12 @@
                 dvbci->language[2] = get8(p, desc_end);
                 dvbci->language[3] = 0;
                 break;
+            case DVB_VBI_DESCID:
+                dvbci->language[0] = get8(p, desc_end);
+                dvbci->language[1] = get8(p, desc_end);
+                dvbci->language[2] = get8(p, desc_end);
+                dvbci->txt_type = (get8(p, desc_end)) >> 3;
+                break;
             default:
                 break;
         }
@@ -1273,10 +1282,10 @@
             codec_type = CODEC_TYPE_AUDIO;
             codec_id = CODEC_ID_DTS;
             break;
-//        case STREAM_TYPE_PRIVATE_DATA:
-//            codec_type = CODEC_TYPE_DATA;
-//            codec_id = CODEC_ID_DVB_VBI;
-//            break;
+        case STREAM_TYPE_VBI_DVB:
+            codec_type = CODEC_TYPE_DATA;
+            codec_id = CODEC_ID_DVB_VBI;
+            break;
         case STREAM_TYPE_SUBTITLE_DVB:
             codec_type = CODEC_TYPE_SUBTITLE;
             codec_id = CODEC_ID_DVB_SUBTITLE;
Index: libs/libavformat/mpegts.h
===================================================================
--- libs/libavformat/mpegts.h	(revision 8570)
+++ libs/libavformat/mpegts.h	(working copy)
@@ -37,6 +37,7 @@
 #define SDT_TID   0x42
 
 /* descriptor ids */
+#define DVB_VBI_DESCID              0x56
 #define DVB_SUBT_DESCID             0x59
 
 #define STREAM_TYPE_VIDEO_MPEG1     0x01
@@ -53,6 +54,7 @@
 #define STREAM_TYPE_AUDIO_DTS       0x8a
 
 #define STREAM_TYPE_SUBTITLE_DVB    0x100
+#define STREAM_TYPE_VBI_DVB         0x101
 
 unsigned int mpegts_crc32(const uint8_t *data, int len);
 extern AVOutputFormat mpegts_mux;
