Index: libs/libmythtv/vbitext/cc.cpp
===================================================================
--- libs/libmythtv/vbitext/cc.cpp	(revision 7892)
+++ libs/libmythtv/vbitext/cc.cpp	(working copy)
@@ -194,34 +194,6 @@
     cc->code1 = -1;
     cc->code2 = -1;
 
-    for (int i = 0; i < 2; i++)
-    {
-        cc->badvbi[i] = 0;
-        cc->lasttc[i] = 0;
-        cc->lastcode[i] = -1;
-        cc->lastcodetc[i] = 0;
-        cc->ccmode[i] = -1;
-        cc->txtmode[i*2 + 0] = 0;
-        cc->txtmode[i*2 + 1] = 0;
-        cc->xds[i] = 0;
-    }
-
-    for (int i = 0; i < 8; i++)
-    {
-        cc->lastrow[i] = 0;
-        cc->newrow[i] = 0;
-        cc->newcol[i] = 0;
-        cc->timecode[i] = 0;
-        cc->row[i] = 0;
-        cc->col[i] = 0;
-        cc->rowcount[i] = 0;
-        cc->style[i] = 0;
-        cc->linecont[i] = 0;
-        cc->resumetext[i] = 0;
-        cc->lastclr[i] = 0;
-        cc->ccbuf[i] = "";
-    }
-
     return cc;
 }
 
Index: libs/libmythtv/vbitext/cc.h
===================================================================
--- libs/libmythtv/vbitext/cc.h	(revision 7892)
+++ libs/libmythtv/vbitext/cc.h	(working copy)
@@ -1,8 +1,6 @@
 #ifndef CC_H
 #define CC_H
 
-#include <qstring.h>
-
 #define CC_VBIBUFSIZE 65536
 
 //cc is 32 columns per row, this allows for extra characters
@@ -14,29 +12,6 @@
     char buffer[CC_VBIBUFSIZE];
     int code1;
     int code2;
-
-    // per-field
-    int badvbi[2];
-    int lasttc[2];
-    int lastcode[2];
-    int lastcodetc[2];
-    int ccmode[2];	// 0=cc1/txt1, 1=cc2/txt2
-    int txtmode[4];
-    int xds[2];
-
-    // per-mode state
-    int lastrow[8];
-    int newrow[8];
-    int newcol[8];
-    int timecode[8];
-    int row[8];
-    int col[8];
-    int rowcount[8];
-    int style[8];
-    int linecont[8];
-    int resumetext[8];
-    int lastclr[8];
-    QString ccbuf[8];
 };
 
 int cc_decode(unsigned char *vbiline);
Index: libs/libmythtv/NuppelVideoRecorder.cpp
===================================================================
--- libs/libmythtv/NuppelVideoRecorder.cpp	(revision 7892)
+++ libs/libmythtv/NuppelVideoRecorder.cpp	(working copy)
@@ -169,6 +169,9 @@
     prev_bframe_save_pos = -1;
 
     volume = 100;
+
+    ccd = new CCDecoder(this);
+
     go7007 = false;
 }
 
@@ -228,6 +231,8 @@
         delete videoFilters;
     if (FiltMan)
         delete FiltMan;
+
+    delete ccd;
 }
 
 void NuppelVideoRecorder::deleteLater(void)
@@ -2463,524 +2468,12 @@
     int tc = (tnow.tv_sec - stm.tv_sec) * 1000 +
              tnow.tv_usec / 1000 - stm.tv_usec / 1000;
 
-    for (int field = 0; field < 2; field++)
-        FormatCCField(cc, tc, field);
+    ccd->FormatCC(tc, cc->code1, cc->code2);
 }
 
-void NuppelVideoRecorder::FormatCCField(struct cc *cc, int tc, int field)
+void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
+                                      long long timecode, char type)
 {
-    const int rowdata[] = { 11, -1, 1, 2, 3, 4, 12, 13,
-                            14, 15, 5, 6, 7, 8, 9, 10 };
-    const QChar specialchar[] =
-    { '®', '°', '½', '¿', 0x2122 /* TM */, '¢', '£', 0x266A /* 1/8 note */,
-      'à', ' ', 'è', 'â', 'ê', 'î', 'ô', 'û'
-    };
-    const QChar extendedchar2[] =
-    { 'Á', 'É', 'Ó', 'Ú', 'Ü', 'ü', '`', '¡',
-      '*', '\'', 0x2014 /* dash */, '©', 0x2120 /* SM */, '·', 0x201C, 0x201D /* dquotes */,
-      'À', 'Â', 'Ç', 'È', 'Ê', 'Ë', 'ë', 'Î',
-      'Ï', 'ï', 'Ô', 'Ù', 'ù', 'Û', '«', '»'
-    };
-    const QChar extendedchar3[] =
-    { 'Ã', 'ã', 'Í', 'Ì', 'ì', 'Ò', 'ò', 'Õ',
-      'õ', '{', '}', '\\', '^', '_', '¦', '~',
-      'Ä', 'ä', 'Ö', 'ö', 'ß', '¥', '¤', '|',
-      'Å', 'å', 'Ø', 'ø', 0x250C, 0x2510, 0x2514, 0x2518 /* box drawing */
-    };
-    int b1, b2, len, x;
-    int mode;
-    int data;
-
-    if (field == 0)
-        data = cc->code1;
-    else
-        data = cc->code2;
-
-    if (data == -1)              // invalid data. flush buffers to be safe.
-    {
-        // TODO: write textbuffer[act]
-        //printf (" TODO: write textbuffer[act]\n");
-        if (cc->ccmode[field] != -1)
-        {
-            for (mode = field*4; mode < (field*4 + 4); mode++)
-                ResetCC(cc, mode);
-            cc->xds[field] = 0;
-            cc->badvbi[field] = 0;
-            cc->ccmode[field] = -1;
-            cc->txtmode[field*2] = 0;
-            cc->txtmode[field*2 + 1] = 0;
-        }
-        return;
-    }
-
-    b1 = data & 0x7f;
-    b2 = (data >> 8) & 0x7f;
-    if (cc->ccmode[field] >= 0)
-    {
-        mode = field << 2 |
-               (cc->txtmode[field*2 + cc->ccmode[field]] << 1) |
-               cc->ccmode[field];
-        len = cc->ccbuf[mode].length();
-    }
-    else
-    {
-        mode = -1;
-        len = 0;
-    }
-
-    // bttv-0.9 VBI reads are pretty reliable (1 read/33367us).
-    // bttv-0.7 reads don't seem to work as well so if read intervals
-    // vary from this, be more conservative in detecting duplicate
-    // CC codes.
-    int dup_text_fudge, dup_ctrl_fudge;
-    if (cc->badvbi[field] < 100 && b1 != 0 && b2 != 0)
-    {
-        int d = tc - cc->lasttc[field];
-        if (d < 25 || d > 42)
-            cc->badvbi[field]++;
-        else if (cc->badvbi[field] > 0)
-            cc->badvbi[field]--;
-    }
-    if (cc->badvbi[field] < 4)
-    {
-        dup_text_fudge = -2;  // should pick up all codes
-        dup_ctrl_fudge = 33 - 4;  // should pick up 1st, 4th, 6th, 8th, ... codes
-    }
-    else
-    {
-        dup_text_fudge = 4;
-        dup_ctrl_fudge = 33 - 4;
-    }
-
-    if (data == cc->lastcode[field])
-    {
-        int false_dup = 1;
-        if ((b1 & 0x70) == 0x10)
-        {
-            if (tc > (cc->lastcodetc[field] + 67 + dup_ctrl_fudge))
-                false_dup = 0;
-        }
-        else if (b1)
-        {
-            // text, XDS
-            if (tc > (cc->lastcodetc[field] + 33 + dup_text_fudge))
-                false_dup = 0;
-        }
-
-        if (false_dup)
-            goto skip;
-    }
-
-    if ((field == 1) &&
-        (cc->xds[field] || b1 && ((b1 & 0x70) == 0x00)))
-        // 0x01 <= b1 <= 0x0F
-        // start XDS
-        // or inside XDS packet
-    {
-        int xds_packet = 1;
-
-        // TODO: process XDS packets
-        if (b1 == 0x0F)
-        {
-            // end XDS
-            cc->xds[field] = 0;
-            xds_packet = 1;
-        }
-        else if ((b1 & 0x70) == 0x10)
-        {
-            // ctrl code -- interrupt XDS
-            cc->xds[field] = 0;
-            xds_packet = 0;
-        }
-        else
-        {
-            cc->xds[field] = 1;
-            xds_packet = 1;
-        }
-
-        if (xds_packet)
-            goto skip;
-    }
-
-    if (b1 & 0x60)
-        // 0x20 <= b1 <= 0x7F
-        // text codes
-    {
-        if (mode >= 0)
-        {
-            cc->lastcodetc[field] += 33;
-            cc->timecode[mode] = tc;
-
-            // commit row number only when first text code
-            // comes in
-            if (cc->newrow[mode])
-                len = NewRowCC(cc, mode, len);
-
-            cc->ccbuf[mode] += CharCC(b1);
-            len++;
-            cc->col[mode]++;
-            if (b2 & 0x60)
-            {
-                cc->ccbuf[mode] += CharCC(b2);
-                len++;
-                cc->col[mode]++;
-            }
-        }
-    }
-
-    else if ((b1 & 0x10) && (b2 > 0x1F))
-        // 0x10 <= b1 <= 0x1F
-        // control codes
-    {
-        cc->lastcodetc[field] += 67;
-
-        int newccmode = (b1 >> 3) & 1;
-        int newtxtmode = cc->txtmode[field*2 + newccmode];
-        if ((b1 & 0x06) == 0x04)
-        {
-            switch (b2)
-            {
-            case 0x29:
-            case 0x2C:
-            case 0x20:
-            case 0x2F:
-            case 0x25:
-            case 0x26:
-            case 0x27:
-                // CC1,2
-                newtxtmode = 0;
-                break;
-            case 0x2A:
-            case 0x2B:
-                // TXT1,2
-                newtxtmode = 1;
-                break;
-            }
-        }
-        cc->ccmode[field] = newccmode;
-        cc->txtmode[field*2 + newccmode] = newtxtmode;
-        mode = (field << 2) | (newtxtmode << 1) | cc->ccmode[field];
-
-        cc->timecode[mode] = tc;
-        len = cc->ccbuf[mode].length();
-
-        if (b2 & 0x40)           //preamble address code (row & indent)
-        {
-            if (newtxtmode)
-                // no address codes in TXT mode?
-                goto skip;
-
-            cc->newrow[mode] = rowdata[((b1 << 1) & 14) | ((b2 >> 5) & 1)];
-            if (cc->newrow[mode] == -1)
-                // bogus code?
-                cc->newrow[mode] = cc->lastrow[mode] + 1;
-
-            if (b2 & 0x10)        //row contains indent flag
-                cc->newcol[mode] = (b2 & 0x0E) << 1;
-            else
-                cc->newcol[mode] = 0;
-
-            // row, indent settings are not final
-            // until text code arrives
-        }
-        else
-        {
-            switch (b1 & 0x07)
-            {
-               case 0x00:          //attribute
-                  /*
-                   printf ("<ATTRIBUTE %d %d>\n", b1, b2);
-                   fflush (stdout);
-                   */
-                   break;
-               case 0x01:          //midrow or char
-                   if (cc->newrow[mode])
-                       len = NewRowCC(cc, mode, len);
-
-                   switch (b2 & 0x70)
-                   {
-                       case 0x20:      //midrow attribute change
-                           // TODO: we _do_ want colors, is that an attribute?
-                           cc->ccbuf[mode] += ' ';
-                           len = cc->ccbuf[mode].length();
-                           cc->col[mode]++;
-                           break;
-                       case 0x30:      //special character..
-                           cc->ccbuf[mode] += specialchar[b2 & 0x0f];
-                           len++;
-                           cc->col[mode]++;
-                           break;
-                   }
-                   break;
-               case 0x02:          //extended char
-                   // extended char is preceded by alternate char
-                   // - if there's no alternate, it could be noise
-                   if (!len)
-                       break;
-
-                   if (b2 & 0x30)
-                   {
-                       cc->ccbuf[mode].remove(len - 1, 1);
-                       cc->ccbuf[mode] += extendedchar2[b2 - 0x20];
-                       len = cc->ccbuf[mode].length();
-                       break;
-                   }
-                   break;
-               case 0x03:          //extended char
-                   // extended char is preceded by alternate char
-                   // - if there's no alternate, it could be noise
-                   if (!len)
-                       break;
-
-                   if (b2 & 0x30)
-                   {
-                       cc->ccbuf[mode].remove(len - 1, 1);
-                       cc->ccbuf[mode] += extendedchar3[b2 - 0x20];
-                       len = cc->ccbuf[mode].length();
-                       break;
-                   }
-                   break;
-               case 0x04:          //misc
-               case 0x05:          //misc + F
-//                 printf("ccmode %d cmd %02x\n",ccmode,b2);
-                   switch (b2)
-                   {
-                       case 0x21:      //backspace
-                           // add backspace if line has been encoded already
-                           if (cc->newrow[mode])
-                               len = NewRowCC(cc, mode, len);
-
-                           if (len == 0 ||
-                               cc->ccbuf[mode].left(1) == "\b")
-                           {
-                               cc->ccbuf[mode] += (char)'\b';
-                               len++;
-                               cc->col[mode]--;
-                           }
-                           else
-                           {
-                               cc->ccbuf[mode].remove(len - 1, 1);
-                               len = cc->ccbuf[mode].length();
-                               cc->col[mode]--;
-                           }
-                           break;
-                       case 0x25:      //2 row caption
-                       case 0x26:      //3 row caption
-                       case 0x27:      //4 row caption
-                           if (cc->style[mode] == CC_STYLE_PAINT && len)
-                           {
-                               // flush
-                               BufferCC(cc, mode, len, 0);
-                               cc->ccbuf[mode] = "";
-                               cc->row[mode] = 0;
-                               cc->col[mode] = 0;
-                           }
-                           else if (cc->style[mode] == CC_STYLE_POPUP)
-                               ResetCC(cc, mode);
-
-                           cc->rowcount[mode] = b2 - 0x25 + 2;
-                           cc->style[mode] = CC_STYLE_ROLLUP;
-                           break;
-                       case 0x2D:      //carriage return
-                           if (cc->style[mode] != CC_STYLE_ROLLUP)
-                               break;
-
-                           if (cc->newrow[mode])
-                               cc->row[mode] = cc->newrow[mode];
-
-                           // flush if there is text or need to scroll
-                           // TODO:  decode ITV (WebTV) link in TXT2
-                           if (len ||
-                               cc->row[mode] != 0 &&
-                               !cc->linecont[mode] &&
-                               (!newtxtmode || cc->row[mode] >= 16))
-                               BufferCC(cc, mode, len, 0);
-
-                           if (newtxtmode)
-                           {
-                               if (cc->row[mode] < 16)
-                                   cc->newrow[mode] = cc->row[mode] + 1;
-                               else
-                                   // scroll up previous lines
-                                   cc->newrow[mode] = 16;
-                           }
-
-                           cc->ccbuf[mode] = "";
-                           cc->col[mode] = 0;
-                           cc->linecont[mode] = 0;
-                           break;
-
-                       case 0x29:      //resume direct caption (paint-on style)
-                           if (cc->style[mode] == CC_STYLE_ROLLUP && len)
-                           {
-                               // flush
-                               BufferCC(cc, mode, len, 0);
-                               cc->ccbuf[mode] = "";
-                               cc->row[mode] = 0;
-                               cc->col[mode] = 0;
-                           }
-                           else if (cc->style[mode] == CC_STYLE_POPUP)
-                               ResetCC(cc, mode);
-
-                           cc->style[mode] = CC_STYLE_PAINT;
-                           cc->rowcount[mode] = 0;
-                           cc->linecont[mode] = 0;
-                           break;
-
-                       case 0x2B:      //resume text display
-                           cc->resumetext[mode] = 1;
-                           if (cc->row[mode] == 0)
-                           {
-                               cc->newrow[mode] = 1;
-                               cc->newcol[mode] = 0;
-                           }
-                           cc->style[mode] = CC_STYLE_ROLLUP;
-                           break;
-                       case 0x2C:      //erase displayed memory
-                           if ((tc - cc->lastclr[mode]) > 5000 ||
-                               cc->lastclr[mode] == 0)
-                               // don't overflow the frontend with
-                               // too many redundant erase codes
-                               BufferCC(cc, mode, 0, 1);
-                           if (cc->style[mode] != CC_STYLE_POPUP)
-                           {
-                               cc->row[mode] = 0;
-                               cc->col[mode] = 0;
-                           }
-                           cc->linecont[mode] = 0;
-                           break;
-
-                       case 0x20:      //resume caption (pop-up style)
-                           if (cc->style[mode] != CC_STYLE_POPUP)
-                           {
-                               if (len)
-                                   // flush
-                                   BufferCC(cc, mode, len, 0);
-                               cc->ccbuf[mode] = "";
-                               cc->row[mode] = 0;
-                               cc->col[mode] = 0;
-                           }
-                           cc->style[mode] = CC_STYLE_POPUP;
-                           cc->rowcount[mode] = 0;
-                           cc->linecont[mode] = 0;
-                           break;
-                       case 0x2F:      //end caption + swap memory
-                           if (cc->style[mode] != CC_STYLE_POPUP)
-                           {
-                               if (len)
-                                   // flush
-                                   BufferCC(cc, mode, len, 0);
-                           }
-                           else if ((tc - cc->lastclr[mode]) > 5000 ||
-                                    cc->lastclr[mode] == 0)
-                               // clear and flush
-                               BufferCC(cc, mode, len, 1);
-                           else if (len)
-                               // flush
-                               BufferCC(cc, mode, len, 0);
-                           cc->ccbuf[mode] = "";
-                           cc->row[mode] = 0;
-                           cc->col[mode] = 0;
-                           cc->style[mode] = CC_STYLE_POPUP;
-                           cc->rowcount[mode] = 0;
-                           cc->linecont[mode] = 0;
-                           break;
-
-                       case 0x2A:      //text restart
-                           // clear display
-                           BufferCC(cc, mode, 0, 1);
-                           ResetCC(cc, mode);
-                           // TXT starts at row 1
-                           cc->newrow[mode] = 1;
-                           cc->newcol[mode] = 0;
-                           cc->style[mode] = CC_STYLE_ROLLUP;
-                           break;
-
-                       case 0x2E:      //erase non-displayed memory
-                           ResetCC(cc, mode);
-                           break;
-                   }
-                   break;
-               case 0x07:          //misc (TAB)
-                   if (cc->newrow[mode])
-                   {
-                       cc->newcol[mode] += (b2 & 0x03);
-                       len = NewRowCC(cc, mode, len);
-                   }
-                   else
-                       // illegal?
-                       for (x = 0; x < (b2 & 0x03); x++)
-                       {
-                           cc->ccbuf[mode] += ' ';
-                           len++;
-                           cc->col[mode]++;
-                       }
-                   break;
-            }
-        }
-    }
-
-skip:
-    for (mode = field*4; mode < (field*4 + 4); mode++)
-    {
-        len = cc->ccbuf[mode].length();
-        if (((tc - cc->timecode[mode]) > 100) &&
-            (cc->style[mode] != CC_STYLE_POPUP) && len)
-        {
-            // flush unfinished line if waiting too long
-            // in paint-on or scroll-up mode
-            cc->timecode[mode] = tc;
-            BufferCC(cc, mode, len, 0);
-            cc->ccbuf[mode] = "";
-            cc->row[mode] = cc->lastrow[mode];
-            cc->linecont[mode] = 1;
-        }
-    }
-
-    if (data != cc->lastcode[field])
-    {
-        cc->lastcode[field] = data;
-        cc->lastcodetc[field] = tc;
-    }
-    cc->lasttc[field] = tc;
-}
-
-QChar NuppelVideoRecorder::CharCC(int code)
-{
-    switch (code)
-    {
-    case 42:  return 'á';
-    case 92:  return 'é';
-    case 94:  return 'í';
-    case 95:  return 'ó';
-    case 96:  return 'ú';
-    case 123: return 'ç';
-    case 124: return '÷';
-    case 125: return 'Ñ';
-    case 126: return 'ñ';
-    case 127: return 0x2588; /* full block */
-    default : return QChar(code);
-    }
-}
-
-void NuppelVideoRecorder::ResetCC(struct cc *cc, int mode)
-{
-//    cc->lastrow[mode] = 0;
-//    cc->newrow[mode] = 0;
-//    cc->newcol[mode] = 0;
-//    cc->timecode[mode] = 0;
-    cc->row[mode] = 0;
-    cc->col[mode] = 0;
-    cc->rowcount[mode] = 0;
-//    cc->style[mode] = CC_STYLE_POPUP;
-    cc->linecont[mode] = 0;
-    cc->resumetext[mode] = 0;
-    cc->lastclr[mode] = 0;
-    cc->ccbuf[mode] = "";
-}
-
-void NuppelVideoRecorder::BufferCC(struct cc *cc, int mode, int len, int clr)
-{
     int act = act_text_buffer;
     if (!textbuffer[act]->freeToBuffer)
     {
@@ -2988,145 +2481,17 @@
         return;
     }
 
-    textbuffer[act]->timecode = cc->timecode[mode];
+    textbuffer[act]->timecode = timecode;
+    memcpy(textbuffer[act]->buffer, buf, len);
+    textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
 
-    // NOTE:  text_buffer_size happens to be > (sizeof(ccsubtitle)+255)
-    QCString tmpbuf;
-    if (len)
-    {
-        // calculate UTF-8 encoding length
-        tmpbuf = cc->ccbuf[mode].utf8();
-        len = tmpbuf.length();
-        if (len > 255)
-            len = 255;
-    }
-
-    unsigned char f;
-    unsigned char *bp = textbuffer[act]->buffer;
-    *(bp++) = cc->row[mode];
-    *(bp++) = cc->rowcount[mode];
-    *(bp++) = cc->style[mode];
-    // overload resumetext field
-    f = cc->resumetext[mode];
-    f |= mode << 4;
-    if (cc->linecont[mode])
-        f |= CC_LINE_CONT;
-    *(bp++) = f;
-    *(bp++) = clr;
-    *(bp++) = len;
-    if (len)
-    {
-        memcpy(bp,
-               tmpbuf,
-               len);
-        textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
-    }
-    else
-        textbuffer[act]->bufferlen = sizeof(ccsubtitle);
-
     textbuffer[act]->freeToBuffer = 0;
     act_text_buffer++;
     if (act_text_buffer >= text_buffer_count)
         act_text_buffer = 0;
     textbuffer[act]->freeToEncode = 1;
-
-    cc->resumetext[mode] = 0;
-    if (clr && !len)
-        cc->lastclr[mode] = cc->timecode[mode];
-    else if (len)
-        cc->lastclr[mode] = 0;
 }
 
-int NuppelVideoRecorder::NewRowCC(struct cc *cc, int mode, int len)
-{
-    if (cc->style[mode] == CC_STYLE_ROLLUP)
-    {
-        // previous line was likely missing a carriage return
-        cc->row[mode] = cc->newrow[mode];
-        if (len)
-        {
-            BufferCC(cc, mode, len, 0);
-            cc->ccbuf[mode] = "";
-            len = 0;
-        }
-        cc->col[mode] = 0;
-        cc->linecont[mode] = 0;
-    }
-    else
-    {
-        // popup/paint style
-
-        if (cc->row[mode] == 0)
-        {
-            if (len == 0)
-                cc->row[mode] = cc->newrow[mode];
-            else
-            {
-                // previous line was missing a row address
-                // - assume it was one row up
-                cc->ccbuf[mode] += (char)'\n';
-                len++;
-                if (cc->row[mode] == 0)
-                    cc->row[mode] = cc->newrow[mode] - 1;
-                else
-                    cc->row[mode]--;
-            }
-        }
-        else if (cc->newrow[mode] > cc->lastrow[mode])
-        {
-            // next line can be more than one row away
-            for (int i = 0; i < (cc->newrow[mode] - cc->lastrow[mode]); i++)
-            {
-                cc->ccbuf[mode] += (char)'\n';
-                len++;
-            }
-            cc->col[mode] = 0;
-        }
-        else if (cc->newrow[mode] == cc->lastrow[mode])
-        {
-            // same row
-            if (cc->newcol[mode] >= cc->col[mode])
-                // new line appends to current line
-                cc->newcol[mode] -= cc->col[mode];
-            else
-            {
-                // new line overwrites current line;
-                // could be legal (overwrite spaces?) but
-                // more likely we have bad address codes
-                // - just move to next line; may exceed row 15
-                // but frontend will adjust
-                cc->ccbuf[mode] += (char)'\n';
-                len++;
-                cc->col[mode] = 0;
-            }
-        }
-        else
-        {
-            // next line goes upwards (not legal?)
-            // - flush
-            BufferCC(cc, mode, len, 0);
-            cc->ccbuf[mode] = "";
-            cc->row[mode] = cc->newrow[mode];
-            cc->col[mode] = 0;
-            cc->linecont[mode] = 0;
-            len = 0;
-        }
-    }
-
-    cc->lastrow[mode] = cc->newrow[mode];
-    cc->newrow[mode] = 0;
-
-    for (int x = 0; x < cc->newcol[mode]; x++)
-    {
-        cc->ccbuf[mode] += ' ';
-        len++;
-        cc->col[mode]++;
-    }
-    cc->newcol[mode] = 0;
-
-    return len;
-}
-
 static void vbi_event(struct VBIData *data, struct vt_event *ev)
 {
     switch (ev->type)
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 7892)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -90,6 +90,7 @@
 HEADERS += recordingtypes.h         jobqueue.h
 HEADERS += filtermanager.h          recordingprofile.h
 HEADERS += remoteencoder.h          videosource.h
+HEADERS += ccdecoder.h
 HEADERS += sr_dialog.h              sr_root.h
 HEADERS += sr_items.h               scheduledrecording.h
 HEADERS += signalmonitorvalue.h 
@@ -104,6 +105,7 @@
 SOURCES += recordingtypes.cpp       jobqueue.cpp
 SOURCES += filtermanager.cpp        recordingprofile.cpp
 SOURCES += remoteencoder.cpp        videosource.cpp
+SOURCES += ccdecoder.cpp
 SOURCES += sr_dialog.cpp            sr_root.cpp
 SOURCES += sr_items.cpp             scheduledrecording.cpp
 SOURCES += signalmonitorvalue.cpp
Index: libs/libmythtv/ccdecoder.h
===================================================================
--- libs/libmythtv/ccdecoder.h	(revision 0)
+++ libs/libmythtv/ccdecoder.h	(revision 0)
@@ -0,0 +1,62 @@
+#ifndef CCDECODER_H_
+#define CCDECODER_H_
+
+#include <qstringlist.h>
+
+#include "format.h"
+
+class CCReader
+{
+  public:
+    virtual ~CCReader() { }
+    virtual void AddTextData(unsigned char *buf, int len, long long timecode, char type) = 0;
+};
+
+class CCDecoder
+{
+  public:
+    CCDecoder(CCReader *ccr);
+    ~CCDecoder();
+
+    void FormatCC(int tc, int code1, int code2);
+    void FormatCCField(int tc, int field, int data);
+                                                          
+  private:
+    QChar CharCC(int code) { return stdchar[code]; }
+    void ResetCC(int mode);
+    void BufferCC(int mode, int len, int clr);
+    int NewRowCC(int mode, int len);
+
+    CCReader *reader;
+
+    // per-field
+    int badvbi[2];
+    int lasttc[2];
+    int lastcode[2];
+    int lastcodetc[2];
+    int ccmode[2];	// 0=cc1/txt1, 1=cc2/txt2
+    int txtmode[4];
+    int xds[2];
+
+    // per-mode state
+    int lastrow[8];
+    int newrow[8];
+    int newcol[8];
+    int timecode[8];
+    int row[8];
+    int col[8];
+    int rowcount[8];
+    int style[8];
+    int linecont[8];
+    int resumetext[8];
+    int lastclr[8];
+    QString ccbuf[8];
+
+    // translation table
+    QChar stdchar[128];
+
+    // temporary buffer
+    unsigned char *rbuf;
+};
+
+#endif
Index: libs/libmythtv/ccdecoder.cpp
===================================================================
--- libs/libmythtv/ccdecoder.cpp	(revision 0)
+++ libs/libmythtv/ccdecoder.cpp	(revision 0)
@@ -0,0 +1,691 @@
+#include <qstringlist.h>
+#include <iostream>
+using namespace std;
+
+#include "format.h"
+#include "ccdecoder.h"
+
+CCDecoder::CCDecoder(CCReader *ccr)
+{
+    reader = ccr;
+
+    for (int i = 0; i < 2; i++)
+    {
+        badvbi[i] = 0;
+        lasttc[i] = 0;
+        lastcode[i] = -1;
+        lastcodetc[i] = 0;
+        ccmode[i] = -1;
+        txtmode[i*2 + 0] = 0;
+        txtmode[i*2 + 1] = 0;
+        xds[i] = 0;
+    }
+
+    for (int i = 0; i < 8; i++)
+    {
+        lastrow[i] = 0;
+        newrow[i] = 0;
+        newcol[i] = 0;
+        timecode[i] = 0;
+        row[i] = 0;
+        col[i] = 0;
+        rowcount[i] = 0;
+        style[i] = 0;
+        linecont[i] = 0;
+        resumetext[i] = 0;
+        lastclr[i] = 0;
+        ccbuf[i] = "";
+    }
+
+    // fill translation table
+    for (int i = 0; i < 128; i++)
+        stdchar[i] = QChar(i);
+
+    // exceptions
+    stdchar[42] = 'á';
+    stdchar[92] = 'é';
+    stdchar[94] = 'í';
+    stdchar[95] = 'ó';
+    stdchar[96] = 'ú';
+    stdchar[123] = 'ç';
+    stdchar[124] = '÷';
+    stdchar[125] = 'Ñ';
+    stdchar[126] = 'ñ';
+    stdchar[127] = 0x2588; /* full block */
+
+    rbuf = new unsigned char[sizeof(ccsubtitle)+255];
+}
+
+CCDecoder::~CCDecoder(void)
+{
+    delete rbuf;
+}
+
+void CCDecoder::FormatCC(int tc, int code1, int code2)
+{
+    FormatCCField(tc, 0, code1);
+    FormatCCField(tc, 1, code2);
+}
+
+void CCDecoder::FormatCCField(int tc, int field, int data)
+{
+    const int rowdata[] = { 11, -1, 1, 2, 3, 4, 12, 13,
+                            14, 15, 5, 6, 7, 8, 9, 10 };
+    const QChar specialchar[] =
+    { '®', '°', '½', '¿', 0x2122 /* TM */, '¢', '£', 0x266A /* 1/8 note */,
+      'à', ' ', 'è', 'â', 'ê', 'î', 'ô', 'û'
+    };
+    const QChar extendedchar2[] =
+    { 'Á', 'É', 'Ó', 'Ú', 'Ü', 'ü', '`', '¡',
+      '*', '\'', 0x2014 /* dash */, '©', 0x2120 /* SM */, '·', 0x201C, 0x201D /* dquotes */,
+      'À', 'Â', 'Ç', 'È', 'Ê', 'Ë', 'ë', 'Î',
+      'Ï', 'ï', 'Ô', 'Ù', 'ù', 'Û', '«', '»'
+    };
+    const QChar extendedchar3[] =
+    { 'Ã', 'ã', 'Í', 'Ì', 'ì', 'Ò', 'ò', 'Õ',
+      'õ', '{', '}', '\\', '^', '_', '¦', '~',
+      'Ä', 'ä', 'Ö', 'ö', 'ß', '¥', '¤', '|',
+      'Å', 'å', 'Ø', 'ø', 0x250C, 0x2510, 0x2514, 0x2518 /* box drawing */
+    };
+    int b1, b2, len, x;
+    int mode;
+
+    if (data == -1)              // invalid data. flush buffers to be safe.
+    {
+        // TODO:  flush reader buffer
+        if (ccmode[field] != -1)
+        {
+            for (mode = field*4; mode < (field*4 + 4); mode++)
+                ResetCC(mode);
+            xds[field] = 0;
+            badvbi[field] = 0;
+            ccmode[field] = -1;
+            txtmode[field*2] = 0;
+            txtmode[field*2 + 1] = 0;
+        }
+        return;
+    }
+
+    b1 = data & 0x7f;
+    b2 = (data >> 8) & 0x7f;
+//    printf("%10d:  %02x %02x\n", tc, b1, b2);
+    if (ccmode[field] >= 0)
+    {
+        mode = field << 2 |
+               (txtmode[field*2 + ccmode[field]] << 1) |
+               ccmode[field];
+        len = ccbuf[mode].length();
+    }
+    else
+    {
+        mode = -1;
+        len = 0;
+    }
+
+    // bttv-0.9 VBI reads are pretty reliable (1 read/33367us).
+    // bttv-0.7 reads don't seem to work as well so if read intervals
+    // vary from this, be more conservative in detecting duplicate
+    // CC codes.
+    int dup_text_fudge, dup_ctrl_fudge;
+    if (badvbi[field] < 100 && b1 != 0 && b2 != 0)
+    {
+        int d = tc - lasttc[field];
+        if (d < 25 || d > 42)
+            badvbi[field]++;
+        else if (badvbi[field] > 0)
+            badvbi[field]--;
+    }
+    if (badvbi[field] < 4)
+    {
+        dup_text_fudge = -2;  // should pick up all codes
+        dup_ctrl_fudge = 33 - 4;  // should pick up 1st, 4th, 6th, 8th, ... codes
+    }
+    else
+    {
+        dup_text_fudge = 4;
+        dup_ctrl_fudge = 33 - 4;
+    }
+
+    if (data == lastcode[field])
+    {
+        int false_dup = 1;
+        if ((b1 & 0x70) == 0x10)
+        {
+            if (tc > (lastcodetc[field] + 67 + dup_ctrl_fudge))
+                false_dup = 0;
+        }
+        else if (b1)
+        {
+            // text, XDS
+            if (tc > (lastcodetc[field] + 33 + dup_text_fudge))
+                false_dup = 0;
+        }
+
+        if (false_dup)
+            goto skip;
+    }
+
+    if ((field == 1) &&
+        (xds[field] || b1 && ((b1 & 0x70) == 0x00)))
+        // 0x01 <= b1 <= 0x0F
+        // start XDS
+        // or inside XDS packet
+    {
+        int xds_packet = 1;
+
+        // TODO: process XDS packets
+        if (b1 == 0x0F)
+        {
+            // end XDS
+            xds[field] = 0;
+            xds_packet = 1;
+        }
+        else if ((b1 & 0x70) == 0x10)
+        {
+            // ctrl code -- interrupt XDS
+            xds[field] = 0;
+            xds_packet = 0;
+        }
+        else
+        {
+            xds[field] = 1;
+            xds_packet = 1;
+        }
+
+        if (xds_packet)
+            goto skip;
+    }
+
+    if (b1 & 0x60)
+        // 0x20 <= b1 <= 0x7F
+        // text codes
+    {
+        if (mode >= 0)
+        {
+            lastcodetc[field] += 33;
+            timecode[mode] = tc;
+
+            // commit row number only when first text code
+            // comes in
+            if (newrow[mode])
+                len = NewRowCC(mode, len);
+
+            ccbuf[mode] += CharCC(b1);
+            len++;
+            col[mode]++;
+            if (b2 & 0x60)
+            {
+                ccbuf[mode] += CharCC(b2);
+                len++;
+                col[mode]++;
+            }
+        }
+    }
+
+    else if ((b1 & 0x10) && (b2 > 0x1F))
+        // 0x10 <= b1 <= 0x1F
+        // control codes
+    {
+        lastcodetc[field] += 67;
+
+        int newccmode = (b1 >> 3) & 1;
+        int newtxtmode = txtmode[field*2 + newccmode];
+        if ((b1 & 0x06) == 0x04)
+        {
+            switch (b2)
+            {
+            case 0x29:
+            case 0x2C:
+            case 0x20:
+            case 0x2F:
+            case 0x25:
+            case 0x26:
+            case 0x27:
+                // CC1,2
+                newtxtmode = 0;
+                break;
+            case 0x2A:
+            case 0x2B:
+                // TXT1,2
+                newtxtmode = 1;
+                break;
+            }
+        }
+        ccmode[field] = newccmode;
+        txtmode[field*2 + newccmode] = newtxtmode;
+        mode = (field << 2) | (newtxtmode << 1) | ccmode[field];
+
+        timecode[mode] = tc;
+        len = ccbuf[mode].length();
+
+        if (b2 & 0x40)           //preamble address code (row & indent)
+        {
+            if (newtxtmode)
+                // no address codes in TXT mode?
+                goto skip;
+
+            newrow[mode] = rowdata[((b1 << 1) & 14) | ((b2 >> 5) & 1)];
+            if (newrow[mode] == -1)
+                // bogus code?
+                newrow[mode] = lastrow[mode] + 1;
+
+            if (b2 & 0x10)        //row contains indent flag
+                newcol[mode] = (b2 & 0x0E) << 1;
+            else
+                newcol[mode] = 0;
+
+            // row, indent settings are not final
+            // until text code arrives
+        }
+        else
+        {
+            switch (b1 & 0x07)
+            {
+               case 0x00:          //attribute
+                  /*
+                   printf ("<ATTRIBUTE %d %d>\n", b1, b2);
+                   fflush (stdout);
+                   */
+                   break;
+               case 0x01:          //midrow or char
+                   if (newrow[mode])
+                       len = NewRowCC(mode, len);
+
+                   switch (b2 & 0x70)
+                   {
+                       case 0x20:      //midrow attribute change
+                           // TODO: we _do_ want colors, is that an attribute?
+                           ccbuf[mode] += ' ';
+                           len = ccbuf[mode].length();
+                           col[mode]++;
+                           break;
+                       case 0x30:      //special character..
+                           ccbuf[mode] += specialchar[b2 & 0x0f];
+                           len++;
+                           col[mode]++;
+                           break;
+                   }
+                   break;
+               case 0x02:          //extended char
+                   // extended char is preceded by alternate char
+                   // - if there's no alternate, it could be noise
+                   if (!len)
+                       break;
+
+                   if (b2 & 0x30)
+                   {
+                       ccbuf[mode].remove(len - 1, 1);
+                       ccbuf[mode] += extendedchar2[b2 - 0x20];
+                       len = ccbuf[mode].length();
+                       break;
+                   }
+                   break;
+               case 0x03:          //extended char
+                   // extended char is preceded by alternate char
+                   // - if there's no alternate, it could be noise
+                   if (!len)
+                       break;
+
+                   if (b2 & 0x30)
+                   {
+                       ccbuf[mode].remove(len - 1, 1);
+                       ccbuf[mode] += extendedchar3[b2 - 0x20];
+                       len = ccbuf[mode].length();
+                       break;
+                   }
+                   break;
+               case 0x04:          //misc
+               case 0x05:          //misc + F
+//                 printf("ccmode %d cmd %02x\n",ccmode,b2);
+                   switch (b2)
+                   {
+                       case 0x21:      //backspace
+                           // add backspace if line has been encoded already
+                           if (newrow[mode])
+                               len = NewRowCC(mode, len);
+
+                           if (len == 0 ||
+                               ccbuf[mode].left(1) == "\b")
+                           {
+                               ccbuf[mode] += (char)'\b';
+                               len++;
+                               col[mode]--;
+                           }
+                           else
+                           {
+                               ccbuf[mode].remove(len - 1, 1);
+                               len = ccbuf[mode].length();
+                               col[mode]--;
+                           }
+                           break;
+                       case 0x25:      //2 row caption
+                       case 0x26:      //3 row caption
+                       case 0x27:      //4 row caption
+                           if (style[mode] == CC_STYLE_PAINT && len)
+                           {
+                               // flush
+                               BufferCC(mode, len, 0);
+                               ccbuf[mode] = "";
+                               row[mode] = 0;
+                               col[mode] = 0;
+                           }
+                           else if (style[mode] == CC_STYLE_POPUP)
+                               ResetCC(mode);
+
+                           rowcount[mode] = b2 - 0x25 + 2;
+                           style[mode] = CC_STYLE_ROLLUP;
+                           break;
+                       case 0x2D:      //carriage return
+                           if (style[mode] != CC_STYLE_ROLLUP)
+                               break;
+
+                           if (newrow[mode])
+                               row[mode] = newrow[mode];
+
+                           // flush if there is text or need to scroll
+                           // TODO:  decode ITV (WebTV) link in TXT2
+                           if (len ||
+                               row[mode] != 0 &&
+                               !linecont[mode] &&
+                               (!newtxtmode || row[mode] >= 16))
+                               BufferCC(mode, len, 0);
+
+                           if (newtxtmode)
+                           {
+                               if (row[mode] < 16)
+                                   newrow[mode] = row[mode] + 1;
+                               else
+                                   // scroll up previous lines
+                                   newrow[mode] = 16;
+                           }
+
+                           ccbuf[mode] = "";
+                           col[mode] = 0;
+                           linecont[mode] = 0;
+                           break;
+
+                       case 0x29:      //resume direct caption (paint-on style)
+                           if (style[mode] == CC_STYLE_ROLLUP && len)
+                           {
+                               // flush
+                               BufferCC(mode, len, 0);
+                               ccbuf[mode] = "";
+                               row[mode] = 0;
+                               col[mode] = 0;
+                           }
+                           else if (style[mode] == CC_STYLE_POPUP)
+                               ResetCC(mode);
+
+                           style[mode] = CC_STYLE_PAINT;
+                           rowcount[mode] = 0;
+                           linecont[mode] = 0;
+                           break;
+
+                       case 0x2B:      //resume text display
+                           resumetext[mode] = 1;
+                           if (row[mode] == 0)
+                           {
+                               newrow[mode] = 1;
+                               newcol[mode] = 0;
+                           }
+                           style[mode] = CC_STYLE_ROLLUP;
+                           break;
+                       case 0x2C:      //erase displayed memory
+                           if ((tc - lastclr[mode]) > 5000 ||
+                               lastclr[mode] == 0)
+                               // don't overflow the frontend with
+                               // too many redundant erase codes
+                               BufferCC(mode, 0, 1);
+                           if (style[mode] != CC_STYLE_POPUP)
+                           {
+                               row[mode] = 0;
+                               col[mode] = 0;
+                           }
+                           linecont[mode] = 0;
+                           break;
+
+                       case 0x20:      //resume caption (pop-up style)
+                           if (style[mode] != CC_STYLE_POPUP)
+                           {
+                               if (len)
+                                   // flush
+                                   BufferCC(mode, len, 0);
+                               ccbuf[mode] = "";
+                               row[mode] = 0;
+                               col[mode] = 0;
+                           }
+                           style[mode] = CC_STYLE_POPUP;
+                           rowcount[mode] = 0;
+                           linecont[mode] = 0;
+                           break;
+                       case 0x2F:      //end caption + swap memory
+                           if (style[mode] != CC_STYLE_POPUP)
+                           {
+                               if (len)
+                                   // flush
+                                   BufferCC(mode, len, 0);
+                           }
+                           else if ((tc - lastclr[mode]) > 5000 ||
+                                    lastclr[mode] == 0)
+                               // clear and flush
+                               BufferCC(mode, len, 1);
+                           else if (len)
+                               // flush
+                               BufferCC(mode, len, 0);
+                           ccbuf[mode] = "";
+                           row[mode] = 0;
+                           col[mode] = 0;
+                           style[mode] = CC_STYLE_POPUP;
+                           rowcount[mode] = 0;
+                           linecont[mode] = 0;
+                           break;
+
+                       case 0x2A:      //text restart
+                           // clear display
+                           BufferCC(mode, 0, 1);
+                           ResetCC(mode);
+                           // TXT starts at row 1
+                           newrow[mode] = 1;
+                           newcol[mode] = 0;
+                           style[mode] = CC_STYLE_ROLLUP;
+                           break;
+
+                       case 0x2E:      //erase non-displayed memory
+                           ResetCC(mode);
+                           break;
+                   }
+                   break;
+               case 0x07:          //misc (TAB)
+                   if (newrow[mode])
+                   {
+                       newcol[mode] += (b2 & 0x03);
+                       len = NewRowCC(mode, len);
+                   }
+                   else
+                       // illegal?
+                       for (x = 0; x < (b2 & 0x03); x++)
+                       {
+                           ccbuf[mode] += ' ';
+                           len++;
+                           col[mode]++;
+                       }
+                   break;
+            }
+        }
+    }
+
+skip:
+    for (mode = field*4; mode < (field*4 + 4); mode++)
+    {
+        len = ccbuf[mode].length();
+        if (((tc - timecode[mode]) > 100) &&
+            (style[mode] != CC_STYLE_POPUP) && len)
+        {
+            // flush unfinished line if waiting too long
+            // in paint-on or scroll-up mode
+            timecode[mode] = tc;
+            BufferCC(mode, len, 0);
+            ccbuf[mode] = "";
+            row[mode] = lastrow[mode];
+            linecont[mode] = 1;
+        }
+    }
+
+    if (data != lastcode[field])
+    {
+        lastcode[field] = data;
+        lastcodetc[field] = tc;
+    }
+    lasttc[field] = tc;
+}
+
+void CCDecoder::ResetCC(int mode)
+{
+//    lastrow[mode] = 0;
+//    newrow[mode] = 0;
+//    newcol[mode] = 0;
+//    timecode[mode] = 0;
+    row[mode] = 0;
+    col[mode] = 0;
+    rowcount[mode] = 0;
+//    style[mode] = CC_STYLE_POPUP;
+    linecont[mode] = 0;
+    resumetext[mode] = 0;
+    lastclr[mode] = 0;
+    ccbuf[mode] = "";
+}
+
+void CCDecoder::BufferCC(int mode, int len, int clr)
+{
+    QCString tmpbuf;
+    if (len)
+    {
+        // calculate UTF-8 encoding length
+        tmpbuf = ccbuf[mode].utf8();
+        len = tmpbuf.length();
+        if (len > 255)
+            len = 255;
+    }
+
+    unsigned char f;
+    unsigned char *bp = rbuf;
+    *(bp++) = row[mode];
+    *(bp++) = rowcount[mode];
+    *(bp++) = style[mode];
+    // overload resumetext field
+    f = resumetext[mode];
+    f |= mode << 4;
+    if (linecont[mode])
+        f |= CC_LINE_CONT;
+    *(bp++) = f;
+    *(bp++) = clr;
+    *(bp++) = len;
+    if (len)
+    {
+        memcpy(bp,
+               tmpbuf,
+               len);
+        len += sizeof(ccsubtitle);
+    }
+    else
+        len = sizeof(ccsubtitle);
+
+    reader->AddTextData(rbuf, len, timecode[mode], 'C');
+
+    resumetext[mode] = 0;
+    if (clr && !len)
+        lastclr[mode] = timecode[mode];
+    else if (len)
+        lastclr[mode] = 0;
+}
+
+int CCDecoder::NewRowCC(int mode, int len)
+{
+    if (style[mode] == CC_STYLE_ROLLUP)
+    {
+        // previous line was likely missing a carriage return
+        row[mode] = newrow[mode];
+        if (len)
+        {
+            BufferCC(mode, len, 0);
+            ccbuf[mode] = "";
+            len = 0;
+        }
+        col[mode] = 0;
+        linecont[mode] = 0;
+    }
+    else
+    {
+        // popup/paint style
+
+        if (row[mode] == 0)
+        {
+            if (len == 0)
+                row[mode] = newrow[mode];
+            else
+            {
+                // previous line was missing a row address
+                // - assume it was one row up
+                ccbuf[mode] += (char)'\n';
+                len++;
+                if (row[mode] == 0)
+                    row[mode] = newrow[mode] - 1;
+                else
+                    row[mode]--;
+            }
+        }
+        else if (newrow[mode] > lastrow[mode])
+        {
+            // next line can be more than one row away
+            for (int i = 0; i < (newrow[mode] - lastrow[mode]); i++)
+            {
+                ccbuf[mode] += (char)'\n';
+                len++;
+            }
+            col[mode] = 0;
+        }
+        else if (newrow[mode] == lastrow[mode])
+        {
+            // same row
+            if (newcol[mode] >= col[mode])
+                // new line appends to current line
+                newcol[mode] -= col[mode];
+            else
+            {
+                // new line overwrites current line;
+                // could be legal (overwrite spaces?) but
+                // more likely we have bad address codes
+                // - just move to next line; may exceed row 15
+                // but frontend will adjust
+                ccbuf[mode] += (char)'\n';
+                len++;
+                col[mode] = 0;
+            }
+        }
+        else
+        {
+            // next line goes upwards (not legal?)
+            // - flush
+            BufferCC(mode, len, 0);
+            ccbuf[mode] = "";
+            row[mode] = newrow[mode];
+            col[mode] = 0;
+            linecont[mode] = 0;
+            len = 0;
+        }
+    }
+
+    lastrow[mode] = newrow[mode];
+    newrow[mode] = 0;
+
+    for (int x = 0; x < newcol[mode]; x++)
+    {
+        ccbuf[mode] += ' ';
+        len++;
+        col[mode]++;
+    }
+    newcol[mode] = 0;
+
+    return len;
+}
+
Index: libs/libmythtv/NuppelVideoRecorder.h
===================================================================
--- libs/libmythtv/NuppelVideoRecorder.h	(revision 7892)
+++ libs/libmythtv/NuppelVideoRecorder.h	(working copy)
@@ -30,6 +30,7 @@
 // MythTV headers
 #include "recorderbase.h"
 #include "format.h"
+#include "ccdecoder.h"
 
 struct video_audio;
 struct VBIData;
@@ -40,7 +41,7 @@
 class FilterManager;
 class FilterChain;
 
-class NuppelVideoRecorder : public RecorderBase
+class NuppelVideoRecorder : public RecorderBase, public CCReader
 {
  public:
     NuppelVideoRecorder(TVRec *rec, ChannelBase *channel);
@@ -131,11 +132,7 @@
 
     void FormatTeletextSubtitles(struct VBIData *vbidata);
     void FormatCC(struct cc *cc);
-    void FormatCCField(struct cc *cc, int tc, int field);
-    QChar CharCC(int code);
-    void ResetCC(struct cc *cc, int mode);
-    void BufferCC(struct cc *cc, int mode, int len, int clr);
-    int NewRowCC(struct cc *cc, int mode, int len);
+    void AddTextData(unsigned char *buf, int len, long long timecode, char type);
     
     bool encoding;
     
@@ -281,6 +278,9 @@
     bool correct_bttv;
 
     int volume;
+
+    CCDecoder *ccd;
+
     bool go7007;
 };
 
