From Wen-King Su, wen-king@myri.com These are sample mpegs from a ReplayTV DVR. They are uploaded for Sascha Sommer and Diego Biurrun. These mpeg files contain Closed Caption information in user_data records that are store in locations and formats different from that in the DVD, and therefore are not recognized by the stock process_userdata function in libmpdemux/video.c. replay_mpeg.4kn replay_mpeg.5kn These are samples from 4000 and 5000 serie ReplayTV. They contain the normal closed caption stream -- the same kind of stream found in movie DVDs. To make them work, I modified process_userdata in libmpdemux/video.c to recognize their unique user_data records, and to pass the stream on to the stock CC decoder module through a new function in sub_cc.c. replay_mpeg.5ks This is a recording from a program with scrolling closed caption. The same mods above will pass the stream to the stock CC decoder module, but the module does not correctly handle a scrolling closed caption stream. For one thing, it never call "display_buffer" for such a stream. Secondly, as it accumulate undisplayed lines, it overflows a fixed sized line array with no bound check. Causing the mplayer to die. My patch below made further changes to sub_cc.c to allow it handle scrolling captions. ================================================== diff -ruN MPlayer-1.0pre5.orig/libmpdemux/video.c MPlayer-1.0pre5/libmpdemux/video.c --- MPlayer-1.0pre5.orig/libmpdemux/video.c Sun Apr 11 12:03:12 2004 +++ MPlayer-1.0pre5/libmpdemux/video.c Wed Oct 20 16:01:45 2004 @@ -287,18 +287,37 @@ } void ty_processuserdata( unsigned char* buf, int len ); +void replay_subcc_process_data(unsigned char b1, unsigned char b2); static void process_userdata(unsigned char* buf,int len){ int i; + static int normal_cc = 0; /* if the user data starts with "CC", assume it is a CC info packet */ if(len>2 && buf[0]=='C' && buf[1]=='C'){ // mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"video.c: process_userdata() detected Closed Captions!\n"); if(subcc_enabled) subcc_process_data(buf+2,len-2); + normal_cc = 1; } if( len > 2 && buf[ 0 ] == 'T' && buf[ 1 ] == 'Y' ) { ty_processuserdata( buf + 2, len - 2 ); return; + } + if(!normal_cc && subcc_enabled) + { + if(len == 10 && buf[0] == 0x99 && buf[1] == 0x02 && + buf[4] == 0xAA && buf[5] == 0x02) + { + replay_subcc_process_data(buf[2],buf[3]); /* RTV5K series */ + return; + } + + if(len == 8 && buf[0] == 0xBB && buf[1] == 0x02 && + buf[4] == 0xCC && buf[5] == 0x02) + { + replay_subcc_process_data(buf[6],buf[7]); /* RTV4K series */ + return; + } } if(verbose<2) return; printf( "user_data: len=%3d %02X %02X %02X %02X '", diff -ruN MPlayer-1.0pre5.orig/sub_cc.c MPlayer-1.0pre5/sub_cc.c --- MPlayer-1.0pre5.orig/sub_cc.c Wed Nov 6 15:54:21 2002 +++ MPlayer-1.0pre5/sub_cc.c Wed Oct 20 17:01:18 2004 @@ -66,6 +66,20 @@ for(i=0;itext[i]) {free(buf->text[i]);buf->text[i]=NULL;} } +static void scroll_buffer() +{ + int i; + + if(bb->lines > 3) + { + free(bb->text[0]); + + for(i = 0; i < (bb->lines - 1); i++) bb->text[i] = bb->text[i+1]; + + bb->text[bb->lines-1] = 0; + bb->lines = bb->lines-1; + } +} void subcc_init() { @@ -93,7 +107,12 @@ if(c=='\n') { if(cursor_pos>0) - bb->lines++;cursor_pos=0; + { + bb->lines++; + bb->text[bb->lines - 1]=malloc(CC_MAX_LINE_LENGTH); + memset(bb->text[bb->lines - 1],0,CC_MAX_LINE_LENGTH); + } + cursor_pos=0; } else { @@ -164,7 +183,11 @@ { case 0x2C: display_buffer(NULL); //EDM clear_buffer(fb); break; + case 0x26: display_buffer(bb); + break; case 0x2d: append_char('\n'); //carriage return + scroll_buffer(); + display_buffer(bb); break; case 0x2e: clear_buffer(bb); //ENM break; @@ -291,3 +314,9 @@ subcc_decode(); } + +void replay_subcc_process_data(unsigned char b1, unsigned char b2) +{ + if(!inited) subcc_init(); + cc_decode_EIA608(b1 | (b2 << 8)); +}