Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 7892)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -158,8 +158,10 @@
       frame_decoded(0), directrendering(false), drawband(false), bitrate(0),
       gopset(false), seen_gop(false), seq_count(0), firstgoppos(0),
       prevgoppos(0), gotvideo(false), lastvpts(0), lastapts(0),
+      lastccptsu(0),
       using_null_videoout(use_null_videoout), video_codec_id(kCodec_NONE),
       maxkeyframedist(-1), 
+      ccd(new CCDecoder(this)),
       // Audio
       audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]),
       audio_sample_size(-1), audio_sampling_rate(-1), audio_channels(-1),
@@ -173,11 +175,14 @@
 
     bool debug = (bool)(print_verbose_messages & VB_LIBAV);
     av_log_set_level((debug) ? AV_LOG_DEBUG : AV_LOG_ERROR);
+
+    save_cctc[0] = save_cctc[1] = 0;
 }
 
 AvFormatDecoder::~AvFormatDecoder()
 {
     CloseContext();
+    delete ccd;
     delete d;
     if (audioSamples)
         delete [] audioSamples;
@@ -308,6 +313,8 @@
 
     lastapts = 0;
     lastvpts = 0;
+    lastccptsu = 0;
+    save_cctc[0] = save_cctc[1] = 0;
 
     av_read_frame_flush(ic);
     
@@ -893,6 +900,9 @@
                 {
                     d->InitMPEG2();
                 }
+
+                enc->decode_cc_dvd = decode_cc_dvd;
+                enc->decode_cc_atsc = decode_cc_atsc;
                 break;
             }
             case CODEC_TYPE_AUDIO:
@@ -1231,6 +1241,187 @@
         cerr<<"render_slice_xvmc called with bad avctx or src"<<endl;
 }
 
+void decode_cc_dvd(struct AVCodecContext *s, const uint8_t *buf, int buf_size)
+{
+    // taken from xine-lib libspucc by Christian Vogler
+
+    AvFormatDecoder *nd = (AvFormatDecoder *)(s->opaque);
+    unsigned long long utc = nd->lastccptsu;
+
+    const uint8_t *current = buf;
+    int curbytes = 0;
+    uint8_t data1, data2;
+    uint8_t cc_code;
+    int odd_offset = 1;
+
+    while (curbytes < buf_size)
+    {
+        int skip = 2;
+
+        cc_code = *current++;
+        curbytes++;
+    
+        if (buf_size - curbytes < 2)
+            break;
+    
+        data1 = *current;
+        data2 = *(current + 1);
+    
+        switch (cc_code)
+        {
+            case 0xfe:
+                /* expect 2 byte encoding (perhaps CC3, CC4?) */
+                /* ignore for time being */
+                skip = 2;
+                break;
+
+            case 0xff:
+            {
+                /* expect EIA-608 CC1/CC2 encoding */
+                int tc = utc / 1000;
+                int data = (data2 << 8) | data1;
+                nd->ccd->FormatCCField(tc, 0, data);
+                utc += 33367;
+                skip = 5;
+                break;
+            }
+
+            case 0x00:
+                /* This seems to be just padding */
+                skip = 2;
+                break;
+
+            case 0x01:
+                odd_offset = data2 & 0x80;
+                if (odd_offset)
+                    skip = 2;
+                else
+                    skip = 5;
+                break;
+
+            default:
+                // rest is not needed?
+                goto done;
+                //skip = 2;
+                //break;
+        }
+        current += skip;
+        curbytes += skip;
+
+    }
+done:
+    nd->lastccptsu = utc;
+}
+
+void decode_cc_atsc(struct AVCodecContext *s, const uint8_t *buf, int buf_size)
+{
+    AvFormatDecoder *nd = (AvFormatDecoder *)(s->opaque);
+    unsigned long long utc = nd->lastccptsu;
+
+    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;
+
+    if (buf_size < 2)
+        return;
+
+    // check process_cc_data_flag
+    if (!(*current & 0x40))
+        return;
+    cc_count = *current & 0x1f;
+    current++;  curbytes++;
+
+    // skip em_data
+    current++;  curbytes++;
+
+    cc_state = 0;
+    while (curbytes < buf_size && curcount < cc_count)
+    {
+        cc_code = *current++;
+        curbytes++;
+    
+        if (buf_size - curbytes < 2)
+            break;
+    
+        data1 = *current++;
+        data2 = *current++;
+        curbytes += 2;
+        curcount++;
+
+        // check cc_valid
+        if (!(cc_code & 0x04))
+            continue;
+
+        cc_code &= 0x03;
+        switch (cc_code)
+        {
+            case 0x00:
+            case 0x01:
+                // EIA-608 field-1/2
+                int data = (data2 << 8) | data1;
+                unsigned int tc;
+
+                if ((cc_state & cc_code) == cc_code)
+                {
+                    // another field of same type -- assume
+                    // it's for the next frame
+                    utc += 33367;
+                    cc_state = 0;
+                }
+                cc_state |= cc_code;
+                tc = utc / 1000;
+
+                // For some reason, one frame can be out of order.
+                // We need to save the CC codes for at least one
+                // frame so we can send the correct sequence to the
+                // decoder.
+
+                if (nd->save_cctc[cc_code])
+                {
+                    if (nd->save_cctc[cc_code] < 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;
+                    }
+                    else if ((nd->save_cctc[cc_code] - tc) > 1000)
+                    {
+                        // saved code is too far in the future; probably bad
+                        // - discard it
+                        nd->save_cctc[cc_code] = 0;
+                    }
+                    else
+                    {
+                        // send new code to decoder
+                        nd->ccd->FormatCCField(tc, cc_code, data);
+                    }
+                }
+                if (!nd->save_cctc[cc_code])
+                {
+                    // 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;
+                }
+                break;
+            case 0x02:
+                // TODO:  EIA-708 DTVCC packet data
+                break;
+            case 0x03:
+                // TODO:  EIA-708 DTVCC packet start
+                break;
+        }
+
+    }
+    nd->lastccptsu = utc;
+}
+
 void AvFormatDecoder::HandleGopStart(AVPacket *pkt)
 {
     if (prevgoppos != 0 && keyframedist != 1)
@@ -1406,7 +1597,7 @@
 
                         gopset = false;
                         prevgoppos = 0;
-                        lastapts = lastvpts = 0;
+                        lastapts = lastvpts = lastccptsu = 0;
                     }
 
                     seq_count++;
@@ -2023,6 +2214,10 @@
                 }
                 case CODEC_TYPE_VIDEO:
                 {
+                    if (firstloop && pts != (int64_t)AV_NOPTS_VALUE)
+                        lastccptsu = (long long)(av_q2d(curstream->time_base) *
+                                                 pkt->pts * 1000000);
+
                     if (onlyvideo < 0)
                     {
                         framesPlayed++;
@@ -2221,3 +2416,9 @@
     return len;  // consume whole frame even if len > enc_len ?
 }
 
+void AvFormatDecoder::AddTextData(unsigned char *buf, int len,
+                                  long long timecode, char type)
+{
+    m_parent->AddTextData((char *)buf, len, timecode, type);
+}
+
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 7892)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -7,6 +7,7 @@
 #include "programinfo.h"
 #include "format.h"
 #include "decoderbase.h"
+#include "ccdecoder.h"
 
 extern "C" {
 #include "frame.h"
@@ -24,7 +25,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
+class AvFormatDecoder : public DecoderBase, public CCReader
 {
     friend void HandleStreamChange(void*);
   public:
@@ -77,6 +78,8 @@
     virtual bool setCurrentAudioTrack(int trackNo);    
     virtual QStringList listAudioTracks() const;
 
+    void AddTextData(unsigned char *buf, int len, long long timecode, char type);
+
     virtual void incCurrentSubtitleTrack();
     virtual void decCurrentSubtitleTrack();
     virtual bool setCurrentSubtitleTrack(int trackNo);    
@@ -106,6 +109,9 @@
     friend void render_slice_xvmc(struct AVCodecContext *c, const AVFrame *src,
                                   int offset[4], int y, int type, int height);
 
+    friend void decode_cc_dvd(struct AVCodecContext *c, const uint8_t *buf, int buf_size);
+    friend void decode_cc_atsc(struct AVCodecContext *c, const uint8_t *buf, int buf_size);
+
     friend int open_avf(URLContext *h, const char *filename, int flags);
     friend int read_avf(URLContext *h, uint8_t *buf, int buf_size);
     friend int write_avf(URLContext *h, uint8_t *buf, int buf_size);
@@ -168,12 +174,17 @@
 
     long long lastvpts;
     long long lastapts;
+    long long lastccptsu;
+    unsigned int save_cctc[2];
+    int save_ccdata[2];
 
     bool using_null_videoout;
     MythCodecID video_codec_id;
 
     int maxkeyframedist;
 
+    CCDecoder *ccd;
+
     // Audio
     short int        *audioSamples;
     int               audio_sample_size;
Index: libs/libavcodec/mpeg12.c
===================================================================
--- libs/libavcodec/mpeg12.c	(revision 7892)
+++ libs/libavcodec/mpeg12.c	(working copy)
@@ -2987,7 +2987,19 @@
                 return;
             avctx->dtg_active_format = p[0] & 0x0f;
         }
+    } else if (len >= 3 &&
+               p[0] == 'C' && p[1] == 'C') {
+        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);
     }
+
 }
 
 static void mpeg_decode_gop(AVCodecContext *avctx, 
Index: libs/libavcodec/utils.c
===================================================================
--- libs/libavcodec/utils.c	(revision 7892)
+++ libs/libavcodec/utils.c	(working copy)
@@ -423,6 +423,12 @@
     return 0;
 }
 
+void avcodec_default_decode_cc_dvd(AVCodecContext *c, const uint8_t *buf, int buf_size){
+}
+
+void avcodec_default_decode_cc_atsc(AVCodecContext *c, const uint8_t *buf, int buf_size){
+}
+
 enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt){
     return fmt[0];
 }
@@ -758,6 +764,9 @@
     s->inter_quant_bias= FF_DEFAULT_QUANT_BIAS;
     s->palctrl = NULL;
     s->reget_buffer= avcodec_default_reget_buffer;
+
+    s->decode_cc_dvd= avcodec_default_decode_cc_dvd;
+    s->decode_cc_atsc= avcodec_default_decode_cc_atsc;
 }
 
 /**
Index: libs/libavcodec/avcodec.h
===================================================================
--- libs/libavcodec/avcodec.h	(revision 7892)
+++ libs/libavcodec/avcodec.h	(working copy)
@@ -1858,6 +1858,14 @@
      */
     int xvmc_vld_hwslice;
 
+    /**
+     * Closed Caption decoder
+     * - encoding: forbidden
+     * - decoding: set by decoder
+     */
+    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);
+
 } AVCodecContext;
 
 /**
@@ -2261,6 +2269,8 @@
 int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count);
 int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count);
 //FIXME func typedef
+void avcodec_default_decode_cc_dvd(AVCodecContext *c, const uint8_t *buf, int buf_size);
+void avcodec_default_decode_cc_atsc(AVCodecContext *c, const uint8_t *buf, int buf_size);
 
 /**
  * opens / inits the AVCodecContext.
