Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 8690)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -14,9 +14,13 @@
 #include "recordingprofile.h"
 #include "videooutbase.h"
 #include "tv_play.h"
+#include "ccdecoder.h"
+#include "cc708decoder.h"
+#include "cc708window.h"
 
 extern "C" {
 #include "filter.h"
+struct PacketBuf;
 }
 using namespace std;
 
@@ -56,7 +60,7 @@
 };
 #define TCTYPESMAX 4
 
-class NuppelVideoPlayer
+class NuppelVideoPlayer : public CCReader, public CC708Reader
 {
  public:
     NuppelVideoPlayer(QString inUseID = "Unknown",
@@ -112,6 +116,9 @@
     void Zoom(int direction);
     void ClearBookmark(void);
 
+    void SetOSDFontName(const QString osdfonts[22], const QString &prefix);
+    void SetOSDThemeName(const QString themename);
+
     // Toggle Sets
     void ToggleLetterbox(int letterboxMode = -1);
 
@@ -222,9 +229,50 @@
     void AddAudioData(char *buffer, int len, long long timecode);
     void AddAudioData(short int *lbuffer, short int *rbuffer, int samples,
                       long long timecode);
-    void AddTextData(char *buffer, int len, long long timecode, char type);
+    void AddTextData(unsigned char *buffer, int len,
+                     long long timecode, char type);
     void AddSubtitle(const AVSubtitle& subtitle);
 
+    // ATSC EIA-708 Captions
+    CC708Window &GetCCWin(uint service_num, uint window_id)
+        { return CC708services[service_num].windows[window_id]; }
+    CC708Window &GetCCWin(uint svc_num)
+        { return GetCCWin(svc_num, CC708services[svc_num].current_window); }
+
+    void SetCurrentWindow(uint service_num, int window_id);
+    void DefineWindow(uint service_num,     int window_id,
+                      int priority,         int visible,
+                      int anchor_point,     int anchor_vertical,
+                      int anchor_horizontal,
+                      int row_count,        int column_count,
+                      int row_lock,         int column_lock,
+                      int pen_style,        int window_style);
+    void DeleteWindows( uint service_num,   int window_map);
+    void DisplayWindows(uint service_num,   int window_map);
+    void HideWindows(   uint service_num,   int window_map);
+    void ClearWindows(  uint service_num,   int window_map);
+    void ToggleWindows( uint service_num,   int window_map);
+    void SetWindowAttributes(uint service_num,
+                             int fill_color,     int fill_opacity,
+                             int border_color,   int border_type,
+                             int scroll_dir,     int print_dir,
+                             int effect_dir,
+                             int display_effect, int effect_speed,
+                             int justify,        int word_wrap);
+    void SetPenAttributes(uint service_num, int pen_size,
+                          int offset,       int text_tag,  int font_tag,
+                          int edge_type,    int underline, int italics);
+    void SetPenColor(uint service_num,
+                     int fg_color, int fg_opacity,
+                     int bg_color, int bg_opacity,
+                     int edge_color);
+    void SetPenLocation(uint service_num, int row, int column);
+
+    void Delay(uint service_num, int tenths_of_seconds);
+    void DelayCancel(uint service_num);
+    void Reset(uint service_num);
+    void TextWrite(uint service_num, short* unicode_string, short len);
+
     // Audio Track Selection
     void incCurrentAudioTrack(void);
     void decCurrentAudioTrack(void);
@@ -474,6 +522,13 @@
     long long osdSubtitlesExpireAt;
     MythDeque<AVSubtitle> nonDisplayedSubtitles;
 
+    CC708Service CC708services[64];
+    QString    osdfontname;
+    QString    osdccfontname;
+    QString    osd708fontnames[20];
+    QString    osdprefix;
+    QString    osdtheme;
+
     // OSD stuff
     OSD      *osd;
     OSDSet   *timedisplay;
Index: libs/libmythtv/cc708window.cpp
===================================================================
--- libs/libmythtv/cc708window.cpp	(revision 0)
+++ libs/libmythtv/cc708window.cpp	(revision 0)
@@ -0,0 +1,159 @@
+// -*- Mode: c++ -*-
+// Copyright (c) 2003-2005, Daniel Kristjansson 
+
+#include <algorithm>
+using namespace std;
+
+#include "cc708window.h"
+
+/************************************************************************
+
+    FCC Addons to EIA-708.
+
+    * Decoders must support the standard, large, and small caption sizes
+      and must allow the caption provider to choose a size and allow the
+      viewer to choose an alternative size.
+
+    * Decoders must support the eight fonts listed in EIA-708. Caption
+      providers may specify 1 of these 8 font styles to be used to write
+      caption text. Decoders must include the ability for consumers to
+      choose among the eight fonts. The decoder must display the font
+      chosen by the caption provider unless the viewer chooses a different
+      font.
+
+    * Decoders must implement the same 8 character background colors
+      as those that Section 9 requires be implemented for character
+      foreground (white, black, red, green, blue, yellow, magenta and cyan).
+
+    * Decoders must implement options for altering the appearance of
+      caption character edges.
+
+    * Decoders must display the color chosen by the caption provider,
+      and must allow viewers to override the foreground and/or background
+      color chosen by the caption provider and select alternate colors.
+
+    * Decoders must be capable of decoding and processing data for the
+      six standard services, but information from only one service need
+      be displayed at a given time.
+
+    * Decoders must include an option that permits a viewer to choose a
+      setting that will display captions as intended by the caption
+      provider (a default). Decoders must also include an option that
+      allows a viewer's chosen settings to remain until the viewer
+      chooses to alter these settings, including during periods when
+      the television is turned off.
+
+    * Cable providers and other multichannel video programming
+      distributors must transmit captions in a format that will be
+      understandable to this decoder circuitry in digital cable
+      television sets when transmitting programming to digital
+      television devices. 
+
+******************************************************************************/
+
+CC708Window::CC708Window()
+    : priority(0),              visible(0),
+      anchor_point(0),
+      anchor_vertical(0),       anchor_horizontal(0),
+      row_count(0),             column_count(0),
+      row_lock(0),              column_lock(0),
+      pen_style(0),             window_style(0),
+
+      fill_color(0),            fill_opacity(0),
+      border_color(0),          border_type(0),
+      scroll_dir(0),            print_dir(0),
+      effect_dir(0),            display_effect(0),
+      effect_speed(0),
+      justify(0),               word_wrap(0),
+
+      true_row_count(0),        true_column_count(0),
+      text(NULL),               exists(false),
+      lock(true)
+{
+}
+
+CC708Window::~CC708Window()
+{
+    if (text)
+        delete [] text;
+}
+
+void CC708Window::Clear(void)
+{
+}
+
+void CC708Window::SetWindowStyle(uint style)
+{
+}
+
+void CC708Window::AddChar(QChar ch)
+{
+    GetCCChar().attr      = pen.attr;
+    GetCCChar().character = ch;
+    IncrPenLocation();
+}
+
+enum
+{
+    LEFT_TO_RIGHT = 0,
+    RIGHT_TO_LEFT = 1,
+    TOP_TO_BOTTOM = 2,
+    BOTTOM_TO_TOP = 3,
+};
+
+void CC708Window::IncrPenLocation(void)
+{
+    // TODO: Scroll direction and up/down printing, and
+    // word wrap not handled yet...
+
+    pen.column += (print_dir == LEFT_TO_RIGHT) ? +1 : 0;
+    pen.column += (print_dir == RIGHT_TO_LEFT) ? -1 : 0;
+    pen.row    += (print_dir == TOP_TO_BOTTOM) ? +1 : 0;
+    pen.row    += (print_dir == BOTTOM_TO_TOP) ? -1 : 0;
+
+    if (1)
+    {
+        // basic wrapping for l->r, r->l languages
+        if (pen.column > true_column_count - 1)
+        {
+            pen.column  = 0;
+            pen.row    += 1;
+        }
+        else if (pen.column < 0)
+        {
+            pen.column  = true_column_count - 1;
+            pen.row    -= 1;
+        }
+    }
+    LimitPenLocation();
+}
+
+void CC708Window::SetPenLocation(uint row, uint column)
+{
+    pen.row    = row;
+    pen.column = column;
+
+    LimitPenLocation();
+}
+
+void CC708Window::LimitPenLocation(void)
+{
+    // basic limiting
+    pen.column = max(pen.column, true_column_count - 1);
+    pen.column = min(pen.column, 0);
+    pen.row    = max(pen.row,    true_row_count - 1);
+    pen.row    = min(pen.row,    0);
+}
+
+/***************************************************************************/
+
+void CC708Pen::SetPenStyle(uint style)
+{
+}
+
+CC708Character::CC708Character(const CC708Window &win)
+{
+    attr = win.pen.attr;
+    character = ' ';
+}
+
Index: libs/libmythtv/nuppeldecoder.cpp
===================================================================
--- libs/libmythtv/nuppeldecoder.cpp	(revision 8690)
+++ libs/libmythtv/nuppeldecoder.cpp	(working copy)
@@ -1148,7 +1148,7 @@
             if (getrawframes)
                 StoreRawData(strm);
 
-            GetNVP()->AddTextData((char *)strm, frameheader.packetlength,
+            GetNVP()->AddTextData(strm, frameheader.packetlength,
                                   frameheader.timecode, frameheader.comptype);
         }
     }
@@ -1166,7 +1166,7 @@
             .arg(newKey).arg(skipFrames)
             .arg((doFlush) ? "do" : "don't")
             .arg((discardFrames) ? "do" : "don't"));
-    
+
     DecoderBase::SeekReset(newKey, skipFrames, doFlush, discardFrames);
 
     if (mpa_codec && doFlush)
Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 8690)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -901,7 +901,7 @@
     videoOutput->DrawSlice(frame, x, y, w, h);
 }
 
-void NuppelVideoPlayer::AddTextData(char *buffer, int len,
+void NuppelVideoPlayer::AddTextData(unsigned char *buffer, int len,
                                     long long timecode, char type)
 {
     WrapTimecode(timecode, TC_CC);
@@ -929,6 +929,246 @@
     }
 }
 
+void NuppelVideoPlayer::SetCurrentWindow(uint service_num, int window_id)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("SetCurrentWindow(%1, %2)")
+            .arg(service_num).arg(window_id));
+    CC708services[service_num].current_window = window_id;
+}
+
+void NuppelVideoPlayer::DefineWindow(
+    uint service_num,     int window_id,
+    int priority,         int visible,
+    int anchor_point,
+    int anchor_vertical,  int anchor_horizontal,
+    int row_count,        int column_count,
+    int row_lock,         int column_lock,
+    int pen_style,        int window_style)
+{
+    VERBOSE(VB_IMPORTANT, LOC +
+            QString("DefineWindow(%1, %2)")
+            .arg(service_num).arg(window_id) +
+            QString("\n\t\t\t     prio %1, vis %2, ap %3, av %4, ah %5")
+            .arg(priority).arg(visible).arg(anchor_point)
+            .arg(anchor_vertical).arg(anchor_horizontal) +
+            QString("\n\t\t\t     row_cnt %1, row_lck %2, "
+                    "col_cnt %3, col_lck %4 ")
+            .arg(row_count).arg(row_lock)
+            .arg(column_count).arg(column_lock) +
+            QString("\n\t\t\t     pen style %1, win style %2")
+            .arg(pen_style).arg(window_style));
+
+    CC708services[service_num].current_window = window_id;
+    CC708Window &win = GetCCWin(service_num, window_id);
+
+    QMutexLocker locker(&win.lock);
+
+    win.priority          = priority;
+    win.visible           = visible;
+    win.anchor_point      = anchor_point;
+    win.anchor_vertical   = anchor_vertical;
+    win.anchor_horizontal = anchor_horizontal;
+    win.row_count         = row_count;
+    win.column_count      = column_count;
+    win.row_lock          = row_lock;
+    win.column_lock       = column_lock;
+
+    if ((!pen_style && !win.exists) || pen_style)
+        win.pen.SetPenStyle(pen_style ? pen_style : 1);
+
+    if ((!window_style && !win.exists) || window_style)
+        win.SetWindowStyle(window_style ? window_style : 1);
+
+    // these could be bigger if row/column lock is false, resp.
+    win.true_row_count        = row_count;
+    win.true_column_count     = column_count;
+
+    if (win.text)
+        delete [] win.text;
+    uint num = win.true_row_count * win.true_column_count;
+    win.text = new CC708Character[num](win);
+
+    win.exists            = true;
+}
+
+void NuppelVideoPlayer::DeleteWindows( uint service_num,   int window_map)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("DeleteWindows(%1, 0x%2)")
+            .arg(service_num).arg(window_map,0,16));
+
+    for (uint i=0; i<8; i++)
+    {
+        if (i & window_map)
+            GetCCWin(service_num, i).exists = false;
+    }
+}
+
+void NuppelVideoPlayer::DisplayWindows(uint service_num,   int window_map)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("DisplayWindows(%1, 0x%2)")
+            .arg(service_num).arg(window_map,0,16));
+
+    for (uint i=0; i<8; i++)
+    {
+        if (i & window_map)
+            GetCCWin(service_num, i).visible = true;
+    }
+}
+
+void NuppelVideoPlayer::HideWindows(   uint service_num,   int window_map)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("HideWindows(%1, 0x%2)")
+            .arg(service_num).arg(window_map,0,16));
+
+    for (uint i=0; i<8; i++)
+    {
+        if (i & window_map)
+            GetCCWin(service_num, i).visible = false;
+    }
+}
+
+void NuppelVideoPlayer::ClearWindows(  uint service_num,   int window_map)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("ClearWindows(%1, 0x%2)")
+            .arg(service_num).arg(window_map,0,16));
+
+    for (uint i=0; i<8; i++)
+    {
+        if (i & window_map)
+            GetCCWin(service_num, i).Clear();
+    }
+}
+
+void NuppelVideoPlayer::ToggleWindows( uint service_num,   int window_map)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("ToggleWindows(%1, 0x%2)")
+            .arg(service_num).arg(window_map,0,16));
+
+    for (uint i=0; i<8; i++)
+    {
+        if (i & window_map)
+        {
+            GetCCWin(service_num, i).visible =
+                !GetCCWin(service_num, i).visible;
+        }
+    }
+}
+
+void NuppelVideoPlayer::SetWindowAttributes(
+    uint service_num,
+    int fill_color,     int fill_opacity,
+    int border_color,   int border_type,
+    int scroll_dir,     int print_dir,
+    int effect_dir,
+    int display_effect, int effect_speed,
+    int justify,        int word_wrap)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("SetWindowAttributes(%1...)")
+            .arg(service_num));
+
+    CC708Window &win = GetCCWin(service_num);
+
+    win.fill_color     = fill_color;
+    win.fill_opacity   = fill_opacity;
+    win.border_color   = border_color;
+    win.border_type    = border_type;
+    win.scroll_dir     = scroll_dir;
+    win.print_dir      = print_dir;
+    win.effect_dir     = effect_dir;
+    win.display_effect = display_effect;
+    win.effect_speed   = effect_speed;
+    win.justify        = justify;
+    win.word_wrap      = word_wrap;
+}
+
+void NuppelVideoPlayer::SetPenAttributes(
+    uint service_num, int pen_size,
+    int offset,       int text_tag,  int font_tag,
+    int edge_type,    int underline, int italics)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("SetPenAttributes(%1...)")
+            .arg(service_num));
+
+    CC708CharacterAttribute &attr = GetCCWin(service_num).pen.attr;
+
+    attr.pen_size  = pen_size;
+    attr.offset    = offset;
+    attr.text_tag  = text_tag;
+    attr.font_tag  = font_tag;
+    attr.edge_type = edge_type;
+    attr.underline = underline;
+    attr.italics   = italics;
+}
+
+void NuppelVideoPlayer::SetPenColor(
+    uint service_num,
+    int fg_color, int fg_opacity,
+    int bg_color, int bg_opacity,
+    int edge_color)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("SetPenColor(%1...)")
+            .arg(service_num));
+
+    CC708CharacterAttribute &attr = GetCCWin(service_num).pen.attr;
+
+    attr.fg_color   = fg_color;
+    attr.fg_opacity = fg_opacity;
+    attr.bg_color   = bg_color;
+    attr.bg_opacity = bg_opacity;
+    attr.edge_color = edge_color;
+}
+
+void NuppelVideoPlayer::SetPenLocation(uint service_num, int row, int column)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("SetPenLocation(%1, (%2x%3))")
+            .arg(service_num).arg(row).arg(column));
+    GetCCWin(service_num).SetPenLocation(row, column);
+}
+
+void NuppelVideoPlayer::Delay(uint service_num, int tenths_of_seconds)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("Delay(%1, %2 seconds)")
+            .arg(service_num).arg(tenths_of_seconds * 0.1f));
+}
+
+void NuppelVideoPlayer::DelayCancel(uint service_num)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("DelayCancel(%1)").arg(service_num));
+}
+
+void NuppelVideoPlayer::Reset(uint service_num)
+{
+    VERBOSE(VB_IMPORTANT, LOC + QString("Reset(%1)").arg(service_num));
+    DeleteWindows(service_num, 0x7);
+    DelayCancel(service_num);
+}
+
+void NuppelVideoPlayer::TextWrite(uint service_num,
+                                  short* unicode_string, short len)
+{
+    for (uint i = 0; i < (uint)len; i++)
+        GetCCWin(service_num).AddChar(QChar(unicode_string[i]));
+
+    if (GetOSD())
+        GetOSD()->CC708Updated();
+}
+
+void NuppelVideoPlayer::SetOSDFontName(const QString osdfonts[22],
+                                       const QString &prefix)
+{
+    osdfontname   = QDeepCopy<QString>(osdfonts[0]);
+    osdccfontname = QDeepCopy<QString>(osdfonts[1]); 
+    for (int i = 2; i < 22; i++)
+        osd708fontnames[i - 2] = QDeepCopy<QString>(osdfonts[i]);
+    osdprefix = QDeepCopy<QString>(prefix);
+}
+
+void NuppelVideoPlayer::SetOSDThemeName(const QString themename)
+{
+    osdtheme = QDeepCopy<QString>(themename);
+}
+
+
 void NuppelVideoPlayer::CheckPrebuffering(void)
 {
     if (kVideoOutput_IVTV == forceVideoOutput)
@@ -2237,6 +2477,7 @@
         {            
             osd->DisableFade();
         }
+        osd->SetCC708Service(&CC708services[1]);
     }
 
     playing = true;
@@ -4919,4 +5160,3 @@
     usleep(100000);
     ClearAfterSeek();
 }
-
Index: libs/libmythtv/osd.h
===================================================================
--- libs/libmythtv/osd.h	(revision 8690)
+++ libs/libmythtv/osd.h	(working copy)
@@ -46,6 +46,7 @@
 class QKeyEvent;
 class OSDGenericTree;
 class ccText;
+class CC708Service;
 
 class OSD : public QObject
 {
@@ -68,12 +69,19 @@
                      const QString &callsign, const QString &iconpath,
                      int length);
     void SetChannumText(const QString &text, int length);
+
+    // CC-608 and DVB text captions (not DVB/DVD subtitles).
     void AddCCText(const QString &text, int x, int y, int color, 
                    bool teletextmode = false);
     void ClearAllCCText();
     void UpdateCCText(vector<ccText*> *ccbuf,
-                      int replace = 0, int scroll = 0, bool scroll_prsv = false,
+                      int replace = 0, int scroll = 0,
+                      bool scroll_prsv = false,
                       int scroll_yoff = 0, int scroll_ymax = 15);
+    // CC-708 text captions (for ATSC)
+    void SetCC708Service(const CC708Service *service);
+    void CC708Updated(void);
+
     void SetSettingsText(const QString &text, int length);
 
     void NewDialogBox(const QString &name, const QString &message, 
@@ -140,7 +148,12 @@
     QRect GetSubtitleBounds();
 
  private:
-    void SetDefaults();
+    bool InitDefaults(void);
+    bool InitCC608(void);
+    bool InitCC708(void);
+    bool InitDVBSub(void);
+    bool InitMenu(void);
+
     TTFFont *LoadFont(QString name, int size); 
     QString FindTheme(QString name);
 
@@ -201,6 +214,12 @@
 
     OSDListTreeType *runningTreeMenu;
     QString treeMenuContainer;
+
+    // EIA-708 captions
+    QString fontname;
+    QString ccfontname;
+    QString cc708fontnames[20];
+    QString fontSizeType;
 };
     
 #endif
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 8690)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -18,6 +18,7 @@
 #include "mythdbcon.h"
 #include "iso639.h"
 #include "pespacket.h"
+#include "cc708decoder.h"
 
 #ifdef USING_XVMC
 #include "videoout_xv.h"
@@ -54,7 +55,7 @@
 void render_slice_xvmc(struct AVCodecContext *s, const AVFrame *src,
                        int offset[4], int y, int type, int height);
 void decode_cc_dvd(struct AVCodecContext *c, const uint8_t *buf, int buf_size);
-void decode_cc_atsc(struct AVCodecContext *c, const uint8_t *buf, int buf_size);
+void decode_cc_atsc(struct AVCodecContext *c,const uint8_t *buf, int buf_size);
 
 static void align_dimensions(AVCodecContext *avctx, uint &width, uint &height)
 {
@@ -261,8 +262,9 @@
       lastccptsu(0),
       using_null_videoout(use_null_videoout),
       video_codec_id(kCodec_NONE),
-      maxkeyframedist(-1), 
-      ccd(new CCDecoder(this)),
+      maxkeyframedist(-1),
+      // Closed Caption decoders
+      ccd(new CCDecoder(parent)),     ccd708(new CC708Decoder(parent)),
       // Audio
       audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]),
       allow_ac3_passthru(false),    allow_dts_passthru(false),
@@ -1383,64 +1385,67 @@
     nd->lastccptsu = utc;
 }
 
-void decode_cc_atsc(struct AVCodecContext *s, const uint8_t *buf, int buf_size)
+void decode_cc_atsc(struct AVCodecContext *s, const uint8_t *buf, int sz)
 {
-    AvFormatDecoder *nd = (AvFormatDecoder *)(s->opaque);
+    if (sz < 2)
+        return;
+
+    AvFormatDecoder *nd    = (AvFormatDecoder *)(s->opaque);
     unsigned long long utc = nd->lastccptsu;
+    uint buf_size          = sz;
 
-    const uint8_t *current = buf;
-    int curbytes = 0;
-    int curcount = 0;
-    uint8_t data1, data2;
-    uint8_t cc_count;
-    uint8_t cc_code;
-    int  cc_state;
+    // closed caption data
+    //cc_data() {
+    // reserved                1 0.0   1  
+    // process_cc_data_flag    1 0.1   bslbf 
+    bool process_cc_data = buf[0] & 0x40;
+    if (!process_cc_data)
+        return; // early exit if process_cc_data_flag false
 
-    if (buf_size < 2)
-        return;
+    // additional_data_flag    1 0.2   bslbf 
+    //bool additional_data = buf[0] & 0x20;
+    // cc_count                5 0.3   uimsbf 
+    uint cc_count = buf[0] & 0x1f;
+    // reserved                8 1.0   0xff
+    // em_data                 8 2.0
 
-    // check process_cc_data_flag
-    if (!(*current & 0x40))
-        return;
-    cc_count = *current & 0x1f;
-    current++;  curbytes++;
+    uint index    = 2; // skip reserved & em_data
+    uint curcount = 0;
+    uint cc_state = 0;
 
-    // skip em_data
-    current++;  curbytes++;
-
-    cc_state = 0;
-    while (curbytes < buf_size && curcount < cc_count)
+    while (index < buf_size && curcount < cc_count)
     {
-        cc_code = *current++;
-        curbytes++;
-    
-        if (buf_size - curbytes < 2)
+        if (buf_size < index + 3)
             break;
     
-        data1 = *current++;
-        data2 = *current++;
-        curbytes += 2;
+        uint cc_code = buf[index];
+        uint data1   = buf[index+1];
+        uint data2   = buf[index+2];
+
+        index += 3;
         curcount++;
 
+        bool cc_valid = cc_code & 0x04;
+        uint cc_type  = cc_code & 0x03;
+
         // check cc_valid
-        if (!(cc_code & 0x04))
+        if (!cc_valid)
             continue;
 
-        cc_code &= 0x03;
-        if (cc_code <= 0x1)
+        if (cc_type <= 0x1)
         {
             // EIA-608 field-1/2
             int data = (data2 << 8) | data1;
             unsigned int tc;
 
-            if ((cc_state & cc_code) == cc_code)
+            if ((cc_state & cc_type) == cc_type)
             {
                 // another field of same type -- assume
                 // it's for the next frame
                 utc += 33367;
                 cc_state = 0;
             }
-            cc_state |= cc_code;
+            cc_state |= cc_type;
             tc = utc / 1000;
 
             // For some reason, one frame can be out of order.
@@ -1448,41 +1453,38 @@
             // frame so we can send the correct sequence to the
             // decoder.
 
-            if (nd->save_cctc[cc_code])
+            if (nd->save_cctc[cc_type])
             {
-                if (nd->save_cctc[cc_code] < tc)
+                if (nd->save_cctc[cc_type] < tc)
                 {
                     // send saved code to decoder
-                    nd->ccd->FormatCCField(nd->save_cctc[cc_code],
-                                           cc_code,
-                                           nd->save_ccdata[cc_code]);
-                    nd->save_cctc[cc_code] = 0;
+                    nd->ccd->FormatCCField(nd->save_cctc[cc_type],
+                                           cc_type,
+                                           nd->save_ccdata[cc_type]);
+                    nd->save_cctc[cc_type] = 0;
                 }
-                else if ((nd->save_cctc[cc_code] - tc) > 1000)
+                else if ((nd->save_cctc[cc_type] - tc) > 1000)
                 {
                     // saved code is too far in the future; probably bad
                     // - discard it
-                    nd->save_cctc[cc_code] = 0;
+                    nd->save_cctc[cc_type] = 0;
                 }
                 else
                 {
                     // send new code to decoder
-                    nd->ccd->FormatCCField(tc, cc_code, data);
+                    nd->ccd->FormatCCField(tc, cc_type, data);
                 }
             }
-            if (!nd->save_cctc[cc_code])
+            if (!nd->save_cctc[cc_type])
             {
                 // no saved code
                 // - save new code since it may be out of order
-                nd->save_cctc[cc_code] = tc;
-                nd->save_ccdata[cc_code] = data;
+                nd->save_cctc[cc_type] = tc;
+                nd->save_ccdata[cc_type] = data;
             }
         }
-        else
-        {
-            // TODO:  EIA-708 DTVCC packet data
-        }
-
+        else // EIA-708 CC data
+            nd->ccd708->decode_cc_data(cc_type, data1, data2);
     }
     nd->lastccptsu = utc;
 }
@@ -2515,6 +2517,14 @@
                         continue;
                     }
 
+#if 0
+                    if (mpa_pic.captions.size) {
+			av_log(NULL, AV_LOG_ERROR, "picture # (%i, %i)\n",
+			       mpa_pic.coded_picture_number, 
+			       mpa_pic.display_picture_number);
+                        m_parent->ParseATSCCaptions(&mpa_pic.captions);
+		    }
+#endif
                     VideoFrame *picframe = (VideoFrame *)(mpa_pic.opaque);
 
                     if (!directrendering)
@@ -2819,12 +2829,6 @@
     return enc_len;
 }
 
-void AvFormatDecoder::AddTextData(unsigned char *buf, int len,
-                                  long long timecode, char type)
-{
-    m_parent->AddTextData((char*)buf, len, timecode, type);
-}
-  
 static int DTS_SAMPLEFREQS[16] =
 {
     0,      8000,   16000,  32000,  64000,  128000, 11025,  22050,
Index: libs/libmythtv/osdtypes.cpp
===================================================================
--- libs/libmythtv/osdtypes.cpp	(revision 8690)
+++ libs/libmythtv/osdtypes.cpp	(working copy)
@@ -1,7 +1,7 @@
 #include <qimage.h>
 #include <qmap.h>
 #include <qregexp.h>
-#include <math.h>
+#include <cmath>
 
 #include <iostream>
 using namespace std;
@@ -1897,3 +1897,244 @@
         }
     }
 }
+
+OSDType708CC::OSDType708CC(const QString &name, TTFFont *fonts[60],
+			   int xoff, int yoff, int dispw, int disph) : 
+    OSDType(name)
+{
+    xoffset = xoff;
+    yoffset = yoff;
+    displaywidth  = dispw;
+    displayheight = disph;
+
+    int c[4] = {0, 85, 170, 255};
+
+    for (int i = 0; i < 64; i++)
+	colors[i].setRgb(c[(i>>4)&3], c[(i>>2)&3], c[i&3]);
+
+    for (int i = 0; i < 60; i++)
+        m_fonts[i] = fonts[i];
+}
+
+void OSDType708CC::Draw(OSDSurface *surface, int /*fade*/,
+                        int /*maxfade*/, int /*xoff*/, int /*yoff*/)
+{
+    int ccx = 0, ccy = 0;
+    //TODO
+    //VERBOSE(VB_IMPORTANT, "Draw()");
+    /*
+    int x = (ccx + 3) * displaywidth / 36 + xoffset;
+    int y = ccy * displayheight / 17 + yoffset;
+    int textlength = 0;
+    QString m_message("test");
+    TTFFont* font = m_fonts[0];
+    font->CalcWidth(m_message, &textlength);
+    int maxx = x + textlength;
+    int maxy = y + font->Size() * 3 / 2;
+    font->DrawString(surface, x, y + 2, m_message, maxx, maxy, 255);
+    */
+    QRect rect = QRect(0, 0, 100, 25);
+    OSDTypeBox *m_box = new OSDTypeBox("cc_background", rect);
+    m_box->SetRect(rect);
+
+    m_box->Draw(surface, 0, 0, displaywidth - 2, displayheight - 2);
+    delete m_box;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+void OSDType708CC::DefineWindow(
+    int window_id,    int priority,        int visible, 
+    int anchor_id,    int anchor_vertical, int anchor_horizontal,
+    int row_count,    int col_count,       int row_lock, int col_lock,
+    int pen_style,    int window_style)
+{
+    QString str("DefineWindow(%1, %2, %3,  %4, %5, %6");
+    str.arg(window_id).arg(priority).arg(visible)
+       .arg(anchor_id).arg(anchor_vertical).arg(anchor_horizontal);
+    str.append(QString("%1, %2, %3, %4, %5, %6)")
+               .arg(row_count).arg(col_count).arg(row_lock).arg(col_lock)
+               .arg(pen_style).arg(window_style));
+
+    m_current_window = window_id;
+
+    Window708 win = m_windows[m_current_window];
+    win.anchorPoint =
+    QPoint(anchor_horizontal, anchor_vertical);
+    win.priority  = priority;
+    win.visible   = visible; 
+    win.anchor_id = anchor_id;
+    win.row_count = row_count;
+    win.col_count = col_count;
+    win.row_lock  = row_lock;
+    win.col_lock  = col_lock;
+
+    if (pen_style>0)
+    {
+        win.curPen.font.setStyleHint(
+            (pen_style<4) ? QFont::Serif : QFont::SansSerif);
+        win.curPen.font.setFixedPitch((pen_style&1));
+        win.curPen.textTag           = 0;    // dialog text
+        win.curPen.font.setPointSize(24);    // standard font size
+        win.curPen.offset            = 1;    // normal
+        win.curPen.font.setItalic(false);
+        win.curPen.font.setUnderline(false);
+        win.curPen.edgeType          = 0;    // none
+        win.curPen.foregroundColor   = Qt::white;
+        win.curPen.edgeColor         = Qt::black;
+        win.curPen.backgroundColor   = Qt::black;
+        win.curPen.foregroundOpacity = 3;    // solid
+        win.curPen.backgroundOpacity = (pen_style>5) ? 0:3; // transparent:solid
+    }
+
+    if (window_style>0)
+    {
+        win.justify   = (3==window_style || 6==window_style) ? 2:0; // center:left
+        win.printDir  = (7==window_style) ? 2 : 0; // Top-to-Bottom:Left-to-Right
+        win.scrollDir = (7==window_style) ? 1 : 3; // Right-to-Left:Bottom-to-Top
+        win.wordWrap  = (4<=window_style && window_style<=6) ? true : false;
+        win.displayEffect = 0; // Snap
+        win.effectDir     = 0;
+        win.effectSpeed   = 0;
+        win.fillColor     = Qt::black;
+        win.fillOpacity   = (2==window_style || 5==window_style) ? 0:3; // transparent:solid
+        win.borderType    = 0; // none
+    }
+    VERBOSE(VB_IMPORTANT, str);
+}
+*/
+/*
+void OSDType708CC::SetWindowAttributes(int fill_color,     int fill_opacity,
+                                       int border_color,   int border_type,
+                                       int scroll_dir,     int print_dir,
+                                       int effect_dir,
+                                       int display_effect, int effect_speed,
+                                       int justify,        int word_wrap)
+{
+    VERBOSE(VB_IMPORTANT, "SetWindowAttributes()");
+    if (m_current_window>=0)
+    {
+        Window708 &win = m_windows[m_current_window];
+        win.fillColor     = colors[fill_color&0x3f];
+        win.borderColor   = colors[border_color&0x3f];
+        win.fillOpacity   = fill_opacity;
+        win.borderType    = border_type;
+        win.scrollDir     = scroll_dir;
+        win.printDir      = print_dir;
+        win.effectDir     = effect_dir;
+        win.displayEffect = display_effect;
+        win.effectSpeed   = effect_speed;
+        win.justify       = justify;
+        win.wordWrap      = word_wrap;
+    }
+}
+
+void OSDType708CC::SetPenAttributes(int pen_size,
+                                    int offset,    int text_tag,  int font_tag,
+                                    int edge_type, int underline, int italics)
+{
+    int pointSize[4] = { 18, 24, 30, 24 };
+    VERBOSE(VB_IMPORTANT, "SetPenAttributes()");
+    if (m_current_window>=0)
+    {
+        QFont::StyleHint stylemap[8] =
+        {
+            QFont::AnyStyle,  QFont::Serif,     QFont::Serif,
+            QFont::SansSerif, QFont::SansSerif, QFont::Decorative,
+            QFont::Decorative, QFont::Decorative
+        };
+        bool mono[8] = { true, true, false, true, false, false, false, false };
+        Pen708 &pen = m_windows[m_current_window].curPen;
+        pen.font.setStyleHint(stylemap[font_tag]);
+        pen.font.setFixedPitch(mono[font_tag]);
+
+        pen.font.setPointSize(pointSize[pen_size]);
+        pen.font.setUnderline(underline);
+        pen.font.setItalic(italics);
+        pen.offset = offset;
+        pen.textTag = text_tag;
+        pen.edgeType = edge_type;
+    }
+}
+*/
+/*
+void OSDType708CC::SetPenColor(int fg_color,   int fg_opacity,
+                               int bg_color,   int bg_opacity,
+                               int edge_color)
+{
+    VERBOSE(VB_IMPORTANT, QString("SetPenColor()"));
+    if (m_current_window>=0)
+    {
+        Pen708 &pen = m_windows[m_current_window].curPen;
+        pen.foregroundColor   = colors[fg_color&0x3f];
+        pen.backgroundColor   = colors[bg_color&0x3f];
+        pen.edgeColor         = colors[edge_color&0x3f];
+        pen.foregroundOpacity = fg_opacity;
+        pen.backgroundOpacity = bg_opacity;
+    }
+}
+*/
+/*
+void OSDType708CC::SetPenLocation(int row, int column)
+{
+    VERBOSE(VB_IMPORTANT, QString("SetPenLocation(%1, %2)").arg(row).arg(column));
+    m_windows[m_current_window].cursorPoint = QPoint(column, row);
+}
+*/
+/*
+void OSDType708CC::Delay(int tenths_of_seconds)
+{
+    VERBOSE(VB_IMPORTANT, QString("Delay(%1)").arg(0.1*tenths_of_seconds));
+}
+
+void OSDType708CC::DelayCancel()
+{
+    VERBOSE(VB_IMPORTANT, "DelayCancel()");
+}
+*/
+/*
+void OSDType708CC::Reset()
+{
+    VERBOSE(VB_IMPORTANT, "Reset()");
+    for (int i=0; i<8; i++)
+    {
+        Pen708 &pen = m_windows[i].curPen;
+        pen.offset   = 1;
+        pen.textTag  = 0;
+        pen.edgeType = 0;
+        pen.font.setStyleHint(QFont::Serif);
+        pen.font.setFixedPitch(false);
+        pen.font.setItalic(false);
+        pen.font.setBold(false);
+        pen.font.setUnderline(false);
+        pen.font.setPointSize(24);
+    }
+}
+*/
+/*
+void OSDType708CC::AddCCText(QString str)
+{
+    VERBOSE(VB_IMPORTANT, QString("AddCCText(%1)").arg(str));
+}
+*/
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 8690)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -91,7 +91,8 @@
 HEADERS += recordingtypes.h         jobqueue.h
 HEADERS += filtermanager.h          recordingprofile.h
 HEADERS += remoteencoder.h          videosource.h
-HEADERS += ccdecoder.h
+HEADERS += ccdecoder.h              cc708decoder.h
+HEADERS += cc708window.h
 HEADERS += sr_dialog.h              sr_root.h
 HEADERS += sr_items.h               scheduledrecording.h
 HEADERS += signalmonitorvalue.h     viewschdiff.h
@@ -108,7 +109,8 @@
 SOURCES += recordingtypes.cpp       jobqueue.cpp
 SOURCES += filtermanager.cpp        recordingprofile.cpp
 SOURCES += remoteencoder.cpp        videosource.cpp
-SOURCES += ccdecoder.cpp
+SOURCES += ccdecoder.cpp            cc708decoder.cpp
+SOURCES += cc708window.cpp
 SOURCES += sr_dialog.cpp            sr_root.cpp
 SOURCES += sr_items.cpp             scheduledrecording.cpp
 SOURCES += signalmonitorvalue.cpp
Index: libs/libmythtv/osdtypes.h
===================================================================
--- libs/libmythtv/osdtypes.h	(revision 8690)
+++ libs/libmythtv/osdtypes.h	(working copy)
@@ -8,6 +8,9 @@
 #include <vector>
 #include <qobject.h>
 #include <qregexp.h>
+#include <qcolor.h>
+#include <qfont.h>
+#include "cc708window.h"
 
 using namespace std;
 
@@ -467,5 +470,71 @@
 
     int xoffset, yoffset, displaywidth, displayheight;
 };
+/*
+class Pen708 {
+    friend class OSDType708CC;
+  private:
+    QFont  font;
+    QColor foregroundColor;
+    QColor backgroundColor;
+    QColor edgeColor;
+    int offset;
+    int textTag;
+    int edgeType;
+    int foregroundOpacity; // also used for edge opacity
+    int backgroundOpacity;
+};
 
+class Window708 {
+    friend class OSDType708CC;
+  private:
+    Window708() : anchorPoint(0,0), fillColor("black"), borderColor("white") {}
+    ~Window708() {}
+
+    // Pen Attributes
+    QPoint cursorPoint;
+    QPoint anchorPoint;
+    Pen708 curPen;
+
+    QColor fillColor;
+    QColor borderColor;
+    int fillOpacity; 
+    int borderType;
+    int scrollDir;
+    int printDir;
+    int effectDir;
+    int displayEffect;
+    int effectSpeed;
+    int justify;
+    bool wordWrap;
+
+    int priority; // higher is better
+    int visible; 
+    int anchor_id;
+    int row_count;
+    int col_count;
+    bool row_lock;
+    bool col_lock;
+};
+*/
+class OSDType708CC : public OSDType
+{
+  public:
+    OSDType708CC(const QString &name, TTFFont *fonts[60],
+                 int xoff, int yoff, int dispw, int disph);
+    virtual ~OSDType708CC() {}
+
+    void SetCCService(const CC708Service *service)
+        { cc708data = service; }
+
+    void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+  private:
+    const CC708Service *cc708data;
+
+    TTFFont *m_fonts[60];
+    QColor   colors[64];
+
+    int xoffset, yoffset, displaywidth, displayheight;
+};
+
 #endif
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 8690)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -15,6 +15,7 @@
 #include "../libavformat/avformat.h"
 }
 
+class CC708Decoder;
 class ProgramInfo;
 class MythSqlDatabase;
 
@@ -76,7 +77,7 @@
 /// The AvFormatDecoder is used to decode non-NuppleVideo files.
 /// It's used a a decoder of last resort after trying the NuppelDecoder
 /// and IvtvDecoder (if "USING_IVTV" is defined).
-class AvFormatDecoder : public DecoderBase, public CCReader
+class AvFormatDecoder : public DecoderBase
 {
     friend void HandleStreamChange(void*);
   public:
@@ -232,6 +233,7 @@
 
     // Caption/Subtitle/Teletext decoders
     CCDecoder        *ccd;
+    CC708Decoder     *ccd708;
 
     // Audio
     short int        *audioSamples;
Index: libs/libmythtv/cc708window.h
===================================================================
--- libs/libmythtv/cc708window.h	(revision 0)
+++ libs/libmythtv/cc708window.h	(revision 0)
@@ -0,0 +1,108 @@
+// -*- Mode: c++ -*-
+// Copyright (c) 2003-2005, Daniel Kristjansson 
+
+#ifndef _CC708_WINDOW_
+#define _CC708_WINDOW_
+
+#include <qstring.h>
+#include <qmutex.h>
+
+class CC708CharacterAttribute
+{
+  public:
+    int pen_size;
+    int offset;
+    int text_tag;
+    int font_tag;
+    int edge_type;
+    int underline;
+    int italics;
+
+    int fg_color;
+    int fg_opacity;
+    int bg_color;
+    int bg_opacity;
+    int edge_color;
+};
+
+class CC708Pen
+{
+  public:
+    void SetPenStyle(uint style);
+  public:
+    CC708CharacterAttribute attr;
+
+    int row;
+    int column;
+};
+
+class CC708Window;
+class CC708Character
+{
+  public:
+    CC708Character(const CC708Window &win);
+    CC708CharacterAttribute attr;
+    QChar character;
+};
+
+class CC708Window
+{
+  public:
+    CC708Window();
+    ~CC708Window();
+
+    void Clear(void);
+    void SetWindowStyle(uint);
+
+    void AddChar(QChar);
+    void IncrPenLocation(void);
+    void SetPenLocation(uint, uint);
+    void LimitPenLocation(void);
+
+    CC708Character &GetCCChar(void)
+        { return text[pen.row * true_column_count + pen.column]; }
+
+  public:
+    int priority;
+    int visible;
+    int anchor_point;
+    int anchor_vertical;
+    int anchor_horizontal;
+    int row_count;
+    int column_count;
+    int row_lock;
+    int column_lock;
+    int pen_style;
+    int window_style;
+
+    int fill_color;
+    int fill_opacity;
+    int border_color;
+    int border_type;
+    int scroll_dir;
+    int print_dir;
+    int effect_dir;
+    int display_effect;
+    int effect_speed;
+    int justify;
+    int word_wrap;
+
+    int true_row_count;
+    int true_column_count;
+    CC708Character *text;
+    CC708Pen        pen;
+
+    /// set to false when DeleteWindow is called on the window.
+    bool            exists;
+
+    mutable QMutex  lock;
+};
+
+class CC708Service
+{
+  public:
+    int current_window;
+    CC708Window windows[8];
+};
+
+#endif // _CC708_WINDOW_
Index: libs/libmythtv/cc708decoder.cpp
===================================================================
--- libs/libmythtv/cc708decoder.cpp	(revision 0)
+++ libs/libmythtv/cc708decoder.cpp	(revision 0)
@@ -0,0 +1,695 @@
+// -*- Mode: c++ -*-
+// Copyright (c) 2003-2005, Daniel Kristjansson 
+
+#include <cassert>
+
+#include "mythcontext.h"
+#include "cc708decoder.h"
+
+#define LOC QString("CC708: ")
+#define LOC_ERR QString("CC708, Error: ")
+
+#define DEBUG_CC_SERVICE_2     0
+#define DEBUG_CC_RAWPACKET     0
+#define DEBUG_CC_SERVICE_BLOCK 0
+
+typedef enum
+{
+    NTSC_CC_f1         = 0,
+    NTSC_CC_f2         = 1,
+    DTVCC_PACKET_DATA  = 2,
+    DTVCC_PACKET_START = 3,
+};
+
+const char* cc_types[4] =
+{
+    "NTSC line 21 field 1 closed captions"
+    "NTSC line 21 field 2 closed captions"
+    "DTVCC Channel Packet Data"
+    "DTVCC Channel Packet Start"
+};
+
+static void parse_cc_packet(CC708Reader *cb_cbs, CaptionPacket *pkt);
+
+CC708Reader::CC708Reader()
+{
+    for (uint i=0; i<64; i++)
+    {
+        buf_alloc[i] = 512;
+        buf[i]       = (unsigned char*) malloc(buf_alloc[i]);
+        buf_size[i]  = 0;
+        delayed[i]   = 0;
+
+        temp_str_alloc[i] = 512;
+        temp_str_size[i]  = 0;
+        temp_str[i]       = (short*) malloc(temp_str_alloc[i] * sizeof(short));
+    }
+}
+
+CC708Reader::~CC708Reader()
+{
+}
+
+void CC708Decoder::decode_cc_data(uint cc_type, uint data1, uint data2)
+{
+    if (DTVCC_PACKET_START == cc_type)
+    {
+        //VERBOSE(VB_IMPORTANT, LOC + QString("CC ST data(0x%1 0x%2)")
+        //        .arg(data1,0,16).arg(data2,0,16));
+
+        if (partialPacket.size && reader)
+            parse_cc_packet(reader, &partialPacket);
+
+        partialPacket.data[0] = data1;
+        partialPacket.data[1] = data2;
+        partialPacket.size   = 2;
+    }
+    else if (DTVCC_PACKET_DATA == cc_type)
+    {
+        //VERBOSE(VB_IMPORTANT, LOC + QString("CC Ex data(0x%1 0x%2)")
+        //        .arg(data1,0,16).arg(data2,0,16));
+
+        partialPacket.data[partialPacket.size + 0] = data1;
+        partialPacket.data[partialPacket.size + 1] = data2;
+        partialPacket.size += 2;
+    }
+}
+
+#define DEBUG_CAPTIONS 0
+
+typedef enum
+{
+    NUL  = 0x00,
+    EXT1 = 0x01,
+    ETX  = 0x03,
+    BS   = 0x08,
+    FF   = 0x0C,
+    CR   = 0x0D,
+    HCR  = 0x0E,
+    P16  = 0x18,
+} C0;
+
+typedef enum
+{
+    CW0=0x80, CW1, CW2, CW3, CW4, CW5, CW6, CW7,      
+    CLW,      DSW, HDW, TGW, DLW, DLY, DLC, RST,
+    SPA=0x90, SPC, SPL,                     SWA=0x97,
+    DF0,      DF1, DF2, DF3, DF4, DF5, DF6, DF7,
+} C1;
+
+extern ushort CCtableG0[0x60];
+extern ushort CCtableG1[0x60];
+extern ushort CCtableG2[0x60];
+extern ushort CCtableG3[0x60];
+
+static void append_character(CC708Reader *cc, uint service_num, short ch);
+static void parse_cc_service_stream(CC708Reader *cc, uint service_num);
+static int handle_cc_c0_ext1_p16(CC708Reader *cc, uint service_num, int i);
+static int handle_cc_c1(CC708Reader *cc, uint service_num, int i);
+static int handle_cc_c2(CC708Reader *cc, uint service_num, int i);
+static int handle_cc_c3(CC708Reader *cc, uint service_num, int i);
+
+#define SEND_STR \
+do { \
+    if (cc->temp_str_size[service_num]) \
+    { \
+        cc->TextWrite(service_num, \
+                      cc->temp_str[service_num], \
+                      cc->temp_str_size[service_num]); \
+        cc->temp_str_size[service_num] = 0; \
+    } \
+} while (0)
+
+static void parse_cc_service_stream(CC708Reader* cc, uint service_num)
+{
+    const int blk_size = cc->buf_size[service_num];
+    int blk_start = 0, i = 0;
+
+    for (i = 0; i < blk_size; i++)
+    {
+        if (RST == cc->buf[service_num][i])
+        {        
+            fprintf(stderr, "Reset i(%i)\n", i);
+            cc->Reset(service_num);
+            blk_start = i+1;
+            cc->delayed[service_num] = 0;
+            break;
+        }
+        else if (DLC == cc->buf[service_num][i])
+        {
+            fprintf(stderr, "DelayCancel i(%i)\n", i);
+            cc->DelayCancel(service_num);
+            cc->delayed[service_num] = 0;
+            break;
+        }
+    }
+    if (cc->buf_size[service_num] >= 126)
+        cc->delayed[service_num] = 0;
+    
+/*
+  av_log(NULL, AV_LOG_ERROR,
+  "cc_ss delayed(%i) blk_start(%i) blk_size(%i)\n",
+  cc->delayed, blk_start, blk_size);
+*/
+
+    for (int i = (cc->delayed[service_num]) ? blk_size : blk_start;
+         i < blk_size; )
+    {
+        const int old_i = i;
+        const int code = cc->buf[service_num][i];
+        //fprintf(stderr, "cc(0x%x,i%i) ", code, i);
+        if (0x0 == code)
+        { 
+            i++; 
+        }
+        else if (code <= 0x1f)
+        {
+            // C0 code -- ASCII commands + ext1: C2,C3,G2,G3 + p16: 16 chars
+            i = handle_cc_c0_ext1_p16(cc, service_num, i);
+        }
+        else if (code <= 0x7f)
+        {
+            // G0 code -- mostly ASCII printables
+            short character = CCtableG0[code-0x20];
+            append_character(cc, service_num, character);
+            i++;
+        }
+        else if (code <= 0x9f)
+        {
+            // C1 code -- caption control codes
+            i = handle_cc_c1(cc, service_num, i);
+        }
+        else if (code <= 0xff)
+        {
+            // G1 code -- ISO 8859-1 Latin 1 characters
+            short character = CCtableG1[code-0xA0];
+            append_character(cc, service_num, character);
+            i++;
+        }
+        if ((old_i == i) || cc->delayed[service_num])
+            break;
+    }
+
+    assert(((int)cc->buf_size[service_num]-i)>=0);
+    if ((cc->buf_size[service_num]-i)>0)
+    {
+        memmove(cc->buf[service_num], cc->buf[service_num]+i, cc->buf_size[service_num]-i);
+        cc->buf_size[service_num] -= i;
+    }
+    else
+    {
+        if (0!=(cc->buf_size[service_num]-i))
+        {
+            fprintf(stderr, "parse_cc_service_stream buffer error "
+                    "i(%i) buf_size(%i)\n", i, cc->buf_size[service_num]);
+            for (i=0; (uint)i<cc->buf_size[service_num]; i++)
+                fprintf(stderr, "0x%x ", cc->buf[service_num][i]);
+            fprintf(stderr, "\n");
+        }
+        cc->buf_size[service_num] = 0;
+    }
+}
+
+static int handle_cc_c0_ext1_p16(CC708Reader* cc, uint service_num, int i)
+{
+    // C0 code -- subset of ASCII misc. control codes
+    const int code = cc->buf[service_num][i];
+    if (code<=0xf)
+    {
+        // single byte code
+        if (ETX==code)
+            SEND_STR;
+        else if (BS==code)
+            append_character(cc, service_num, 0x08);
+        else if (FF==code)
+            append_character(cc, service_num, 0x0c);
+        else if (CR==code)
+            append_character(cc, service_num, 0x0d);
+        else if (HCR==code)
+            append_character(cc, service_num, 0x0d);
+        i++;
+    }
+    else if (code<=0x17)
+    {
+        // double byte code
+        const int blk_size = cc->buf_size[service_num];
+        if (EXT1==code && ((i+1)<blk_size))
+        {
+            const int code2 = cc->buf[service_num][i+1];
+            if (code2<=0x1f)
+            {
+                // C2 code -- nothing in EIA-708-A
+                i = handle_cc_c2(cc, service_num, i+1);
+            }
+            else if (code2<=0x7f)
+            {
+                // G2 code -- fractions, drawing, symbols
+                append_character(cc, service_num, CCtableG2[code2-0x20]);
+                i+=2;
+            }
+            else if (code2<=0x9f)
+            {
+                // C3 code -- nothing in EIA-708-A
+                i = handle_cc_c3(cc, service_num, i);
+            }
+            else if (code2<=0xff)
+            {
+                // G3 code -- one symbol in EIA-708-A "[cc]"
+                append_character(cc, service_num, CCtableG3[code2-0xA0]);
+                i+=2;
+            }
+        }
+        else if ((i+1)<blk_size)
+            i+=2;
+    }
+    else if (code<=0x1f)
+    {
+        // triple byte code
+        const int blk_size = cc->buf_size[service_num];
+        if (P16==code && ((i+2)<blk_size))
+        {
+            // reserved for large alphabets, but not yet defined
+        }
+        if ((i+2)<blk_size)
+            i+=3;
+    }
+    return i;
+}
+
+static int handle_cc_c1(CC708Reader* cc, uint service_num, int i)
+{
+    const int blk_size = cc->buf_size[service_num];
+    const int code = cc->buf[service_num][i];
+
+    //fprintf(stderr, "handle_cc_c1(0x%x, %i, %i)\n", code, i, blk_size);
+    const unsigned char* blk_buf = cc->buf[service_num];
+    if (code<=CW7)
+    { // no paramaters
+        SEND_STR;
+        cc->SetCurrentWindow(service_num, code-0x80);
+        i+=1;
+    }
+    else if (DLC == cc->buf[service_num][i])
+    {
+        fprintf(stderr, "DelayCancel i(%i)\n", i);
+        cc->DelayCancel(service_num);
+        cc->delayed[service_num] = 0;
+        i+=1;
+    }
+    else if (code>=CLW && code<=DLY && ((i+1)<blk_size))
+    { // 1 byte of paramaters
+        int param1 = blk_buf[i+1];
+        SEND_STR;
+        if (CLW==code)
+            cc->ClearWindows(service_num, param1);
+        else if (DSW==code)
+            cc->DisplayWindows(service_num, param1);
+        else if (HDW==code)
+            cc->HideWindows(service_num, param1);
+        else if (TGW==code)
+            cc->ToggleWindows(service_num, param1);
+        else if (DLW==code)
+            cc->DeleteWindows(service_num, param1);
+        else if (DLY==code)
+        {
+            fprintf(stderr, "Delay()");
+            cc->Delay(service_num, param1);
+            cc->delayed[service_num] = 1;
+        }
+        i+=2;
+    }
+    else if (SPA==code && ((i+2)<blk_size))
+    {
+        int pen_size  = (blk_buf[i+1]   ) & 0x3;
+        int offset    = (blk_buf[i+1]>>2) & 0x3;
+        int text_tag  = (blk_buf[i+1]>>4) & 0xf;
+        int font_tag  = (blk_buf[i+2]   ) & 0x7;
+        int edge_type = (blk_buf[i+2]>>3) & 0x7;
+        int underline = (blk_buf[i+2]>>4) & 0x1;
+        int italic    = (blk_buf[i+2]>>5) & 0x1;
+        SEND_STR;
+        //fprintf(stderr, "set_pen_attr(0x%08x)(0x%08x, 0x%02x, 0x%02x)\n",
+        //        cc->SetPenAttributes, cc, blk_buf[i+1], blk_buf[i+2]);
+        cc->SetPenAttributes(service_num, pen_size, offset, text_tag,
+                             font_tag, edge_type, underline, italic);
+        i+=3;
+    }
+    else if (SPC==code && ((i+3)<blk_size))
+    {
+        int fg_color   = (blk_buf[i+1]   ) & 0x3f;
+        int fg_opacity = (blk_buf[i+1]>>6) & 0x03;
+        int bg_color   = (blk_buf[i+2]   ) & 0x3f;
+        int bg_opacity = (blk_buf[i+2]>>6) & 0x03;
+        int edge_color = (blk_buf[i+3]>>6) & 0x3f;
+        SEND_STR;
+        //fprintf(stderr, "set_pen_color(0x%08x)(0x%08x, 0x%02x, 0x%02x, 0x%02x)\n",
+        //        cc->SetPenColor, cc, blk_buf[i+1], blk_buf[i+2], blk_buf[i+3]);
+        cc->SetPenColor(service_num, fg_color, fg_opacity,
+                        bg_color, bg_opacity, edge_color);
+        i+=4;
+    }
+    else if (SPL==code && ((i+2)<blk_size))
+    {
+        int row = blk_buf[i+1] & 0x0f;
+        int col = blk_buf[i+2] & 0x3f;
+        SEND_STR;
+        //fprintf(stderr, "set_pen_loc(0x%08x)(0x%08x, 0x%02x, 0x%02x)\n",
+        //        cc->SetPenLocation, cc, blk_buf[i+1], blk_buf[i+2]);
+        cc->SetPenLocation(service_num, row, col);
+        i+=3;
+    }
+    else if (SWA==code && ((i+4)<blk_size))
+    {
+        int fill_color    = (blk_buf[i+1]   ) & 0x3f;
+        int fill_opacity  = (blk_buf[i+1]>>6) & 0x03;
+        int border_color  = (blk_buf[i+2]   ) & 0x3f;
+        int border_type01 = (blk_buf[i+2]>>6) & 0x03;
+        int justify       = (blk_buf[i+3]   ) & 0x03;
+        int scroll_dir    = (blk_buf[i+3]>>2) & 0x03;
+        int print_dir     = (blk_buf[i+3]>>4) & 0x03;
+        int word_wrap     = (blk_buf[i+3]>>6) & 0x01;
+        int border_type   = (blk_buf[i+3]>>5) | border_type01;
+        int display_eff   = (blk_buf[i+4]   ) & 0x03;
+        int effect_dir    = (blk_buf[i+4]>>2) & 0x03;
+        int effect_speed  = (blk_buf[i+4]>>4) & 0x0f;
+        SEND_STR;
+        //fprintf(stderr, "set_win_attr(0x%08x)(0x%08x, 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
+        //        cc->SetWindowAttributes, cc, blk_buf[i+1], blk_buf[i+2], blk_buf[i+3], blk_buf[i+4]);
+        cc->SetWindowAttributes(
+            service_num, fill_color, fill_opacity, border_color, border_type,
+            scroll_dir,     print_dir,    effect_dir,
+            display_eff,    effect_speed, justify, word_wrap);
+        i+=5;
+    }
+    else if ((code>=DF0) && (code<=DF7) && ((i+6)<blk_size))
+    {
+        //fprintf(stderr, "define_window(%i)\n", code-0x98);
+        // param1
+        int priority = ( blk_buf[i+1]  ) & 0x7;
+        int col_lock = (blk_buf[i+1]>>3) & 0x1;
+        int row_lock = (blk_buf[i+1]>>4) & 0x1;
+        int visible  = (blk_buf[i+1]>>5) & 0x1;
+        // param2
+        int anchor_vertical = blk_buf[i+2] & 0x7f;
+        int relative_pos = (blk_buf[i+2]>>7);
+        (void) relative_pos;
+        // param3
+        int anchor_horizontal = blk_buf[i+3];
+        // param4
+        int row_count = blk_buf[i+4] & 0xf;
+        int anchor_point = blk_buf[i+4]>>4;
+        // param5
+        int col_count = blk_buf[i+5] & 0x3f;
+        // param6
+        int pen_style = blk_buf[i+6] & 0x7;
+        int win_style = (blk_buf[i+6]>>3) & 0x7;
+        SEND_STR;
+        cc->DefineWindow(service_num, code-0x98, priority, visible,
+                         anchor_point, anchor_vertical, anchor_horizontal,
+                         row_count, col_count, row_lock, col_lock,
+                         pen_style, win_style);
+        i+=7;
+    }
+    else
+    {
+        fprintf(stderr, "handle_cc_c1: (NOT HANDLED) "
+                "code(0x%02x) i(%i) blk_size(%i)\n", code, i, blk_size);
+    }
+    //fprintf(stderr, "handle_cc_c1, returning %i\n", i);
+    return i;
+}
+
+static int handle_cc_c2(CC708Reader* cc, uint service_num, int i)
+{
+    const int blk_size = cc->buf_size[service_num];
+    const int code = cc->buf[service_num][i+1];
+    fprintf(stderr, "handle_cc_C2(0x%x)\n", code);
+    if ((code<=0x7) && ((i+1)<blk_size)){
+        i+=2;
+        SEND_STR;
+    }
+    else if ((code<=0xf) && ((i+2)<blk_size))
+    {
+        i+=3;
+        SEND_STR;
+    }
+    else if ((code<=0x17) && ((i+3)<blk_size))
+    {
+        i+=4;
+        SEND_STR;
+    }
+    else if ((code<=0x1f) && ((i+4)<blk_size))
+    {
+        i+=5;
+        SEND_STR;
+    }
+    return i;
+}
+
+static int handle_cc_c3(CC708Reader* cc, uint service_num, int i)
+{
+    const unsigned char* blk_buf = cc->buf[service_num];
+    const int blk_size = cc->buf_size[service_num];
+    const int code = cc->buf[service_num][i+1];
+
+    fprintf(stderr, "handle_cc_C3(0x%x)\n", code);
+    if ((code<=0x87) && ((i+5)<blk_size))
+    {
+        i+=6;
+        SEND_STR;
+    }
+    else if ((code<=0x8f) && ((i+6)<blk_size))
+    {
+        i+=7;
+        SEND_STR;
+    }
+    else if ((i+2)<blk_size)
+    { // varible length commands
+        int length = blk_buf[i+2]&0x3f;
+        if ((i+length)<blk_size)
+        {
+            i+=1+length;
+            SEND_STR;
+        }
+    }
+    return i;
+}
+
+static void append_cc(CC708Reader* cc, uint service_num,
+                      const unsigned char* blk_buf, int block_size)
+{
+    assert(cc);
+    assert(block_size + cc->buf_size[service_num] <
+           cc->buf_alloc[service_num]);
+
+    memcpy(cc->buf[service_num] + cc->buf_size[service_num],
+           blk_buf, block_size);
+
+    cc->buf_size[service_num] += block_size;
+#if DEBUG_CC_SERVICE_2
+    {
+        uint i;
+        fprintf(stderr, "append_cc: ");
+        for (i = 0; i < cc->buf_size[service_num]; i++)
+            fprintf(stderr, "0x%x ", cc->buf[service_num][i]);
+        fprintf(stderr, "\n");
+    }
+#endif
+    parse_cc_service_stream(cc, service_num);
+}
+
+static void parse_cc_packet(CC708Reader* cb_cbs, CaptionPacket* pkt)
+{
+    const unsigned char* pkt_buf = pkt->data;
+    const int pkt_size = pkt->size;
+    int off = 1;
+    int service_number = 0;
+    int block_data_offset = 0;
+    int len = ((((int)pkt_buf[0])&0x3f)*2-1)&0xff;
+    int seq_num = (((int)pkt_buf[0])>>6)&0x3;
+
+#if DEBUG_CC_RAWPACKET
+    {
+        int j;
+        fprintf(stderr, "CC length(%2i) seq_num(%i) ", len, seq_num);
+        for (j=1; j<pkt_size; j++)
+            fprintf(stderr, "0x%x ", pkt_buf[j]);
+        fprintf(stderr, "\n");
+    }
+#else
+    (void) seq_num;
+#endif
+
+    assert(pkt_size<127);
+    assert(len<128);
+
+    while (pkt_buf[off] && off<pkt_size)
+    { // service_block
+        int block_size = pkt_buf[off] & 0x1f;
+        service_number = (pkt_buf[off]>>5) & 0x7;
+        block_data_offset = (0x7==service_number && block_size!=0) ? off+2 : off+1;
+#if DEBUG_CC_SERVICE_BLOCK
+        fprintf(stderr, "service_block size(%i) num(%i) off(%i) ",
+                block_size, service_number, block_data_offset);
+#endif
+        if (off+2 == block_data_offset)
+        {
+            int extended_service_number = pkt_buf[off+2] & 0x3f;
+#if DEBUG_CC_SERVICE_BLOCK
+            fprintf(stderr, "ext_svc_num(%i) ", extended_service_number);
+#endif
+            service_number =  extended_service_number;
+        }
+        if (service_number)
+        {
+#if DEBUG_CC_SERVICE
+            int i;
+            if (!(2==block_size &&
+                  0==pkt_buf[block_data_offset] &&
+                  0==pkt_buf[block_data_offset+1]))
+            {
+                fprintf(stderr, "service %i: ", service_number);
+                for (i=0; i<block_size; i++)
+                    fprintf(stderr, "0x%x ", pkt_buf[block_data_offset+i]);
+                fprintf(stderr, "\n");
+            }
+#endif
+            append_cc(cb_cbs, service_number,
+                      &pkt_buf[block_data_offset], block_size);
+        }
+        off+=block_size+1;
+    }
+    if (off<pkt_size) // must end in null service block, if packet is not full.
+        assert(pkt_buf[off]==0);
+}
+
+static void append_character(CC708Reader *cc, uint service_num, short ch)
+{
+    if (cc->temp_str_size[service_num]+2 > cc->temp_str_alloc[service_num])
+    {
+        int new_alloc = (cc->temp_str_alloc[service_num]) ?
+            cc->temp_str_alloc[service_num] * 2 : 64;
+
+        cc->temp_str[service_num] = (short*)
+            realloc(cc->temp_str[service_num], new_alloc * sizeof(short));
+
+        assert(cc->temp_str[service_num]);
+        cc->temp_str_alloc[service_num] = new_alloc; // shorts allocated
+    }
+
+    if (cc->temp_str[service_num])
+    {
+        int i = cc->temp_str_size[service_num];
+        cc->temp_str[service_num][i] = ch;
+        cc->temp_str_size[service_num]++;
+    }
+    else
+    {
+        cc->temp_str_size[service_num] = 0;
+        cc->temp_str_alloc[service_num]=0;
+    }
+}
+
+ushort CCtableG0[0x60] =
+{
+//   0    1    2    3       4    5    6    7
+//   8    9    a    b       c    d    e    f  
+    ' ', '!','\"', '#',    '$', '%', '&', '\'', /* 0x20-0x27 */
+    '(', ')', '*', '+',    ',', '-', '.', '/',  /* 0x28-0x2f */
+    '0', '1', '2', '3',    '4', '5', '6', '7',  /* 0x30-0x37 */
+    '8', '9', ':', ';',    '<', '=', '>', '?',  /* 0x38-0x3f */
+
+    '@', 'A', 'B', 'C',    'D', 'E', 'F', 'G',  /* 0x40-0x47 */
+    'H', 'I', 'J', 'K',    'L', 'M', 'N', 'O',  /* 0x48-0x4f */
+    'P', 'Q', 'R', 'S',    'T', 'U', 'V', 'W',  /* 0x50-0x57 */
+    'X', 'Y', 'Z', '[',    '\\',']', '^', '_',  /* 0x58-0x5f */
+
+    '`', 'a', 'b', 'c',    'd', 'e', 'f', 'g',  /* 0x60-0x67 */
+    'h', 'i', 'j', 'k',    'l', 'm', 'n', 'o',  /* 0x68-0x6f */
+    'p', 'q', 'r', 's',    't', 'u', 'v', 'w',  /* 0x70-0x77 */
+    'x', 'y', 'z', '{',    '|', '}', '~',  0x1d16, // music note /* 0x78-0x7f */
+};
+
+ushort CCtableG1[0x60] =
+{
+//   0    1    2    3       4    5    6    7
+//   8    9    a    b       c    d    e    f  
+    0xA0, // unicode non-breaking space
+         '¡', '¢', '£',    '¤', '¥', '¦', '§', /* 0xa0-0xa7 */
+    '¨', '©', 'ª', '«',    '¬', '­', '®', '¯', /* 0xa8-0xaf */
+    '°', '±', '²', '³',    '´', 'µ', '¶', '·', /* 0xb0-0xb7 */
+    '¸', '¹', 'º', '»',    '¼', '½', '¾', '¿', /* 0xbf-0xbf */
+
+    'À', 'Á', 'Â', 'Ã',    'Ä', 'Å', 'Æ', 'Ç', /* 0xc0-0xc7 */
+    'È', 'É', 'Ê', 'Ë',    'Ì', 'Í', 'Î', 'Ï', /* 0xcf-0xcf */
+    'Ð', 'Ñ', 'Ò', 'Ó',    'Ô', 'Õ', 'Ö', '×', /* 0xd0-0xd7 */
+    'Ø', 'Ù', 'Ú', 'Û',    'Ü', 'Ý', 'Þ', 'ß', /* 0xdf-0xdf */
+
+    'à', 'á', 'â', 'ã',    'ä', 'å', 'æ', 'ç', /* 0xe0-0xe7 */
+    'è', 'é', 'ê', 'ë',    'ì', 'í', 'î', 'ï', /* 0xef-0xef */
+    'ð', 'ñ', 'ò', 'ó',    'ô', 'õ', 'ö', '÷', /* 0xf0-0xf7 */
+    'ø', 'ù', 'ú', 'û',    'ü', 'ý', 'þ', 'ÿ', /* 0xff-0xff */
+};
+
+ushort CCtableG2[0x60] =
+{
+    ' ', /* transparent space */
+                        0xA0, /* non-breaking transparent space */
+    0,                  0,                     /* 0x20-0x23 */
+    0,                  0x2026,/* elipsis */
+    0,                  0,                     /* 0x24-0x27 */
+    0,                  0,
+    0x160,/*S under \/*/0,                     /* 0x28-0x2b */
+    0x152, /* CE */     0,
+    0,                  0,                     /* 0x2c-0x2f */
+    0x2DA, /*super dot*/0x2018,/* open ' */
+    0x2019,/*close ' */ 0x201c,/* open " */    /* 0x30-0x33 */
+    0x201d,/*close " */ '*',   /* dot */
+    0,                  0,                     /* 0x34-0x37 */
+    0,                  '#',   /* super TM */
+    0x161,/*s under \/*/0,                     /* 0x38-0x3b */
+    0x153, /* ce */     '#',   /* super SM */
+    0,                  0x178,/*Y w/umlout*/   /* 0x3c-0x3f */
+    
+//  0         1         2         3
+//  4         5         6         7
+//  8         9         a         b
+//  c         d         e         f  
+    0,        0,        0,        0,
+    0,        0,        0,        0, /* 0x40-0x47 */
+    0,        0,        0,        0,
+    0,        0,        0,        0, /* 0x48-0x4f */
+
+    0,        0,        0,        0,
+    0,        0,        0,        0, /* 0x50-0x57 */
+    0,        0,        0,        0,
+    0,        0,        0,        0, /* 0x58-0x5f */
+
+    0,        0,        0,        0,
+    0,        0,        0,        0, /* 0x60-0x67 */
+    0,        0,        0,        0,
+    0,        0,        0,        0, /* 0x68-0x6f */
+
+    0,                  0,
+    0,                  0,           /* 0x70-0x73 */
+    0,                  0,
+    0x215b, /* 1/8 */   0x215c, /* 3/8 */    /* 0x74-0x77 */
+    0x215d, /* 5/8 */   0x215e, /* 7/8 */
+    0x2502, /*line | */ 0x2510, /*line ~| */ /* 0x78-0x7b */
+    0x2514, /*line |_*/ 0x2500, /*line -*/
+    0x2518, /*line _|*/ 0x250c, /*line |~ */ /* 0x7c-0x7f */
+};
+
+ushort CCtableG3[0x60] =
+{
+//   0 1  2  3    4  5  6  7     8  9  a  b    c  d  e  f  
+    '#', /* [CC] closed captioning logo */
+       0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xa0-0xaf */
+    0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xb0-0xbf */
+
+    0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xc0-0xcf */
+    0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xd0-0xdf */
+
+    0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xe0-0xff */
+    0, 0, 0, 0,   0, 0, 0, 0,    0, 0, 0, 0,   0, 0, 0, 0, /* 0xf0-0xff */
+};
Index: libs/libmythtv/osd.cpp
===================================================================
--- libs/libmythtv/osd.cpp	(revision 8690)
+++ libs/libmythtv/osd.cpp	(working copy)
@@ -28,8 +28,16 @@
 
 #include "osdlistbtntype.h"
 
+static char  *cc708_default_font_names[20];
+static bool   cc708_defaults_initialized = false;
+static QMutex cc708_init_lock;
+static void initialize_osd_fonts(void);
+
 static float sq(float a) { return a*a; }
 
+#define LOC QString("OSD: ")
+#define LOC_ERR QString("OSD, Error: ")
+
 OSD::OSD(const QRect &osd_bounds, int   frameRate,
          const QRect &vis_bounds, float visibleAspect, float fontScaling)
     : QObject(),
@@ -48,6 +56,12 @@
       changed(false),                     runningTreeMenu(NULL),
       treeMenuContainer("")
 {
+    if (!cc708_defaults_initialized)
+        initialize_osd_fonts();
+
+    for (uint i = 0; i < 20; i++)
+        cc708fontnames[i] = cc708_default_font_names[i];
+
     needPillarBox = visibleAspect > 1.51f;
     wscale = visibleAspect / 1.3333f;
     // adjust for wscale font size scaling
@@ -57,7 +71,7 @@
     {
         VERBOSE(VB_IMPORTANT, "Couldn't find OSD theme: "
                 <<gContext->GetSetting("OSDTheme"));
-        SetDefaults();
+        InitDefaults();
         return;
     }
 
@@ -67,9 +81,9 @@
         VERBOSE(VB_IMPORTANT, "Couldn't load OSD theme: "
                 <<gContext->GetSetting("OSDTheme")<<" at "<<themepath);
     }
-    SetDefaults();
+    InitDefaults();
 
-    // Reinit since LoadThemes and SetDefaults() appear to mess things up.
+    // Reinit since LoadThemes and InitDefaults() appear to mess things up.
     Reinit(osd_bounds, frameRate, vis_bounds, visibleAspect, fontScaling);
 }
 
@@ -113,8 +127,19 @@
     }
 }
 
-void OSD::SetDefaults(void)
+bool OSD::InitDefaults(void)
 {
+    bool ok = true;
+    ok &= InitCC608();
+    ok &= InitCC708();
+    ok &= InitMenu();
+    ok &= InitDVBSub();
+    return ok;
+}
+
+bool OSD::InitCC608(void)
+{
+    // EIA-608 captions
     TTFFont *ccfont = GetFont("cc_font");
     if (!ccfont)
     {
@@ -128,7 +153,7 @@
     }
 
     if (!ccfont)
-        return;
+        return false;
 
     OSDSet *container = GetSet("cc_page");
     if (!container)
@@ -157,8 +182,66 @@
                                           sub_dispw, sub_disph);
         container->AddType(ccpage);
     }
+    return true;
+}
 
-    container = GetSet("menu");
+bool OSD::InitCC708(void)
+{
+    VERBOSE(VB_IMPORTANT, LOC + "InitCC708() -- begin");
+    // EIA-708 captions
+    // Check if cc708 osd already exits, exit early if it does
+    QString name("cc708_page");
+    OSDSet *container = GetSet(name);
+    if (container)
+    {
+        VERBOSE(VB_IMPORTANT, LOC + "InitCC708() -- end (already exits)");
+        return true;
+    }
+
+    // Create fonts...
+    TTFFont* ccfonts[60];
+    for (uint i = 0; i < 60; i++)
+    {
+        TTFFont *ccfont = GetFont("cc_font");
+	//TTFFont *ccfont = GetFont(QString("cc708_font%1").arg(i));
+	if (!ccfont)
+	{
+	    QString name = QString("cc708_font%1").arg(i);
+            int fontsizes[3] = { 480/36, 480/27, 480/20 };
+            int fontsize = fontsizes[i%3];
+	    ccfont = LoadFont(gContext->GetSetting("OSDCCFont")
+                              /*cc708fontnames[i/3]*/, fontsize);
+	    if (ccfont)
+		fontMap[name] = ccfont;
+	    if (!ccfont)
+            {
+                VERBOSE(VB_IMPORTANT, LOC_ERR + "A CC708 font is missing");
+		return false;
+            }
+	    ccfonts[i] = ccfont;
+	}
+    }
+
+    // Create a container for one service
+    container = new OSDSet(
+        name, true, osdBounds.width(), osdBounds.height(),
+        wmult, hmult, frameint);
+    container->SetPriority(30);
+
+    AddSet(container, name);
+    OSDType708CC *ccpage = 
+        new OSDType708CC(name, ccfonts, xoffset, yoffset, 
+                         displaywidth, displayheight);
+    container->AddType(ccpage);
+
+    VERBOSE(VB_IMPORTANT, LOC + "InitCC708() -- end");
+    return true;
+}
+
+bool OSD::InitMenu(void)
+{
+    // Menu
+    OSDSet *container = GetSet("menu");
     if (!container)
     {
         QString name = "menu";
@@ -208,9 +291,13 @@
 
         container->AddType(lb);
     }
+    return true;
+}
 
+bool OSD::InitDVBSub(void)
+{
     // Create container for subtitles
-    container = GetSet("subtitles");
+    OSDSet *container = GetSet("subtitles");
     if (!container)
     {
         QString name = "subtitles";
@@ -220,6 +307,7 @@
         container->SetPriority(30);
         AddSet(container, name);
     }
+    return true;
 }
 
 void OSD::Reinit(const QRect &totalBounds,   int   frameRate,
@@ -1664,6 +1752,52 @@
     osdlock.unlock();
 }
 
+void OSD::SetCC708Service(const CC708Service *service)
+{
+    QMutexLocker locker(&osdlock);
+
+    VERBOSE(VB_IMPORTANT, "SetCC708Service() -- 1");
+
+    OSDSet *container = GetSet("cc708_page");
+    if (!container)
+    {
+        VERBOSE(VB_IMPORTANT, "SetCC708Service() -- can't find container");
+        return;
+    }
+
+    OSDType *type = container->GetType("cc708_page");
+    OSDType708CC *ccpage = (OSDType708CC*) type;
+    if (!ccpage)
+    {
+        VERBOSE(VB_IMPORTANT, "SetCC708Service() -- no OSDType708CC");
+        return;
+    }
+
+    VERBOSE(VB_IMPORTANT, "SetCC708Service() -- 2");
+    ccpage->SetCCService(service);
+    container->Display(1/*visible*/);
+    m_setsvisible = true;
+    changed = true;
+}
+
+void OSD::CC708Updated(void)
+{
+    QMutexLocker locker(&osdlock);
+
+    OSDSet *container = GetSet("cc708_page");
+    if (!container)
+        return;
+
+    OSDType *type = container->GetType("cc708_page");
+    OSDType708CC *ccpage = dynamic_cast<OSDType708CC*>(type);
+    if (ccpage)
+    {
+        container->Display(1/*visible*/);
+        m_setsvisible = true;
+        changed = true;
+    }
+}
+
 void OSD::SetSettingsText(const QString &text, int length)
 {
     HideAllExcept("settings");
@@ -2413,3 +2547,56 @@
 {
     return QRect(xoffset, yoffset, displaywidth, displayheight);
 }
+
+static void initialize_osd_fonts(void)
+{
+    QMutexLocker locker(&cc708_init_lock);
+    if (cc708_defaults_initialized)
+        return;
+    cc708_defaults_initialized = true;
+
+    cc708_default_font_names[0]  = strdup(gContext->GetSetting(
+        "OSDCC708MonoSerifFont"));
+    cc708_default_font_names[1]  = strdup(gContext->GetSetting(
+        "OSDCC708MonoSerifItalicFont"));
+    cc708_default_font_names[2]  = strdup(gContext->GetSetting(
+        "OSDCC708PropSerifFont"));
+    cc708_default_font_names[3]  = strdup(gContext->GetSetting(
+        "OSDCC708PropSerifItalicFont"));
+
+    cc708_default_font_names[4]  = strdup(gContext->GetSetting(
+        "OSDCC708MonoSansSerifFont"));
+    cc708_default_font_names[5]  = strdup(gContext->GetSetting(
+        "OSDCC708MonoSansSerifItalicFont"));
+    cc708_default_font_names[6]  = strdup(gContext->GetSetting(
+        "OSDCC708PropSansSerifFont"));
+    cc708_default_font_names[7]  = strdup(gContext->GetSetting(
+        "OSDCC708PropSansSerifItalicFont"));
+
+    cc708_default_font_names[8]  = strdup(gContext->GetSetting(
+        "OSDCC708MonoCasualFont"));
+    cc708_default_font_names[9]  = strdup(gContext->GetSetting(
+        "OSDCC708MonoCasualItalicFont"));
+    cc708_default_font_names[10] = strdup(gContext->GetSetting(
+        "OSDCC708PropCasualFont"));
+    cc708_default_font_names[11] = strdup(gContext->GetSetting(
+        "OSDCC708PropCasualItalicFont"));
+
+    cc708_default_font_names[12] = strdup(gContext->GetSetting(
+        "OSDCC708MonoCursiveFont"));
+    cc708_default_font_names[13] = strdup(gContext->GetSetting(
+        "OSDCC708MonoCursiveItalicFont"));
+    cc708_default_font_names[14] = strdup(gContext->GetSetting(
+        "OSDCC708PropCursiveFont"));
+    cc708_default_font_names[15] = strdup(gContext->GetSetting(
+        "OSDCC708PropCursiveItalicFont"));
+
+    cc708_default_font_names[16] = strdup(gContext->GetSetting(
+        "OSDCC708MonoCapitalsFont"));
+    cc708_default_font_names[17] = strdup(gContext->GetSetting(
+        "OSDCC708MonoCapitalsItalicFont"));
+    cc708_default_font_names[18] = strdup(gContext->GetSetting(
+        "OSDCC708PropCapitalsFont"));
+    cc708_default_font_names[19] = strdup(gContext->GetSetting(
+        "OSDCC708PropCapitalsItalicFont"));
+}
Index: libs/libmythtv/cc708decoder.h
===================================================================
--- libs/libmythtv/cc708decoder.h	(revision 0)
+++ libs/libmythtv/cc708decoder.h	(revision 0)
@@ -0,0 +1,97 @@
+// -*- Mode: c++ -*-
+// Copyright (c) 2003-2005, Daniel Kristjansson 
+
+#ifndef CC708DECODER_H_
+#define CC708DECODER_H_
+
+#include <stdint.h>
+
+#include <qstringlist.h>
+
+#include "format.h"
+
+#ifndef __CC_CALLBACKS_H__
+/** EIA-708-A closed caption packet */
+typedef struct CaptionPacket
+{
+    unsigned char data[128+16];
+    int size;
+} CaptionPacket;
+#endif
+
+class CC708Reader
+{
+  public:
+    CC708Reader();
+    virtual ~CC708Reader();
+
+    // Window settings
+    virtual void SetCurrentWindow(uint service_num, int window_id) = 0;
+    virtual void DefineWindow(uint service_num,     int window_id,
+                              int priority,         int visible,
+                              int anchor_point,     int anchor_vertical,
+                              int anchor_horizontal,
+                              int row_count,        int column_count,
+                              int row_lock,         int column_lock,
+                              int pen_style,        int window_style) = 0;
+    virtual void DeleteWindows( uint service_num,   int window_map) = 0;
+    virtual void DisplayWindows(uint service_num,   int window_map) = 0;
+    virtual void HideWindows(   uint service_num,   int window_map) = 0;
+    virtual void ClearWindows(  uint service_num,   int window_map) = 0;
+    virtual void ToggleWindows( uint service_num,   int window_map) = 0;
+    virtual void SetWindowAttributes(uint service_num,
+                                     int fill_color,     int fill_opacity,
+                                     int border_color,   int border_type,
+                                     int scroll_dir,     int print_dir,
+                                     int effect_dir,
+                                     int display_effect, int effect_speed,
+                                     int justify,        int word_wrap) = 0;
+
+    // Pen settings
+    virtual void SetPenAttributes(uint service_num,
+                                  int pen_size,  int offset,
+                                  int text_tag,  int font_tag,
+                                  int edge_type,
+                                  int underline, int italics) = 0;
+    virtual void SetPenColor(uint service_num,
+                             int fg_color, int fg_opacity,
+                             int bg_color, int bg_opacity,
+                             int edge_color) = 0;
+    virtual void SetPenLocation(uint service_num, int row, int column) = 0;
+
+    // Display State
+    virtual void Delay(uint service_num, int tenths_of_seconds) = 0;
+    virtual void DelayCancel(uint service_num) = 0;
+    virtual void Reset(uint service_num) = 0;
+
+    // Text
+    virtual void TextWrite(uint service_num,
+                           short* unicode_string, short len) = 0;
+
+    // Data
+    unsigned char* buf[64];
+    uint   buf_alloc[64];
+    uint   buf_size[64];
+    bool   delayed[64];
+
+    short* temp_str[64];
+    int    temp_str_alloc[64];
+    int    temp_str_size[64];
+};
+
+class CC708Decoder
+{
+  public:
+    CC708Decoder(CC708Reader *ccr) : reader(ccr)
+        { bzero(&partialPacket, sizeof(CaptionPacket)); }
+
+    ~CC708Decoder();
+
+    void decode_cc_data(uint cc_type, uint data1, uint data2);
+
+  private:
+    CaptionPacket  partialPacket;
+    CC708Reader   *reader;
+};
+
+#endif // CC708DECODER_H_
Index: libs/libavcodec/mpeg12.c
===================================================================
--- libs/libavcodec/mpeg12.c	(revision 8690)
+++ libs/libavcodec/mpeg12.c	(working copy)
@@ -2989,15 +2989,22 @@
         }
     } else if (len >= 3 &&
                p[0] == 'C' && p[1] == 'C') {
+        /* parse DVD Closed Caption data */
         p += 2;
         len -= 2;
         avctx->decode_cc_dvd(avctx, p, len);
     } else if (len >= 6 &&
-               p[0] == 0x47 && p[1] == 0x41 && p[2] == 0x39 && p[3] == 0x34 &&
-               p[4] == 0x03) {
-        p += 5;
-        len -= 5;
-        avctx->decode_cc_atsc(avctx, p, len);
+               p[0] == 'G' && p[1] == 'A' && p[2] == '9' && p[3] == '4') {
+        /* parse ATSC info (EIA-708 Closed Captions && letterbox info) */
+        int user_data_type_code = p[4];
+        if (user_data_type_code == 0x03) { // caption data
+            p += 5;
+            len -= 5;
+            avctx->decode_cc_atsc(avctx, p, len);
+        }
+        else if (user_data_type_code == 0x06) {
+            // bar data (letterboxing info)
+        }
     }
 }
 
