[Mplayer-cvslog] CVS: main sub_cc.c,NONE,1.1 sub_cc.h,NONE,1.1 mplayer.c,1.529,1.530 mencoder.c,1.141,1.142 cfg-common.h,1.49,1.50 Makefile,1.195,1.196

Atmosfear atmos4 at mplayerhq.hu
Thu Jul 25 05:37:30 CEST 2002


Update of /cvsroot/mplayer/main
In directory mail:/var/tmp.root/cvs-serv21348

Modified Files:
	mplayer.c mencoder.c cfg-common.h Makefile 
Added Files:
	sub_cc.c sub_cc.h 
Log Message:
DVD Closed Captioning support, patch by Matteo Giani <matgiani at ctonet.it>, small changes by me.


--- NEW FILE ---
/*
 * sub_cc.c - Decoder for Closed Captions
 *
 * This decoder relies on MPlayer's OSD to display subtitles.
 * Be warned that the decoding is somewhat preliminary, though it basically works.
 * 
 * Most notably, only the text information is decoded as of now, discarding color,
 * background and position info (see source below).
 * 
 * by Matteo Giani
 *
 * uses source from the xine closed captions decoder
 */


#include <stdio.h>
#include <stdlib.h>

#include "subreader.h"

#include "libvo/video_out.h"
#include "libvo/sub.h"


#define CC_INPUTBUFFER_SIZE 256

#define CC_MAX_LINE_LENGTH 64

static char chartbl[128];

extern int subcc_enabled;

subtitle buf1,buf2;
subtitle *fb,*bb;

static unsigned int cursor_pos=0;

static int inited=0;
static unsigned char inputbuffer[CC_INPUTBUFFER_SIZE];
static unsigned int inputlength;

static void build_char_table(void)
{
  int i;
  /* first the normal ASCII codes */
  for (i = 0; i < 128; i++)
    chartbl[i] = (char) i;
  /* now the special codes */
  chartbl[0x2a] = 'á';
  chartbl[0x5c] = 'é';
  chartbl[0x5e] = 'í';
  chartbl[0x5f] = 'ó';
  chartbl[0x60] = 'ú';
  chartbl[0x7b] = 'ç';
  chartbl[0x7c] = '÷';
  chartbl[0x7d] = 'Ñ';
  chartbl[0x7e] = 'ñ';
  chartbl[0x7f] = '¤';    /* FIXME: this should be a solid block */
}

void clear_buffer(subtitle *buf)
{
	int i;
	buf->lines=0;
	for(i=0;i<SUB_MAX_TEXT;i++) if(buf->text[i]) {free(buf->text[i]);buf->text[i]=NULL;}
}


void subcc_init()
{
	int i;
	//printf("subcc_init(): initing...\n");
	build_char_table();
	for(i=0;i<SUB_MAX_TEXT;i++) {buf1.text[i]=buf2.text[i]=NULL;}
	buf1.lines=buf2.lines=0;
	fb=&buf1;
	bb=&buf2;
	
	inited=1;
}

static void append_char(char c)
{
	if(!bb->lines) {bb->lines++; cursor_pos=0;}
	if(bb->text[bb->lines - 1]==NULL) 
	{
		bb->text[bb->lines - 1]=malloc(CC_MAX_LINE_LENGTH);
		memset(bb->text[bb->lines - 1],0,CC_MAX_LINE_LENGTH);
		cursor_pos=0;
	}
	
	if(c=='\n')
	{
		if(cursor_pos>0)
			bb->lines++;cursor_pos=0;
	}
	else 
	{
		if(cursor_pos==CC_MAX_LINE_LENGTH-1)
		{
			printf("sub_cc.c: append_char() reached CC_MAX_LINE_LENGTH!\n");
			return;
		}
		bb->text[bb->lines - 1][cursor_pos++]=c;
	}
}


static void swap_buffers()
{
	subtitle *foo;
	foo=fb;
	fb=bb;
	bb=foo;
}

static void display_buffer(subtitle * buf)
{
	vo_sub=buf;
	vo_osd_changed(OSDTYPE_SUBTITLE);
}


static void cc_decode_EIA608(unsigned short int data)
{
  
  static unsigned short int lastcode=0x0000;	
  unsigned char c1 = data & 0x7f;
  unsigned char c2 = (data >> 8) & 0x7f;

  if (c1 & 0x60) {		/* normal character, 0x20 <= c1 <= 0x7f */
	   append_char(chartbl[c1]);
	   if(c2 & 0x60)	/*c2 might not be a normal char even if c1 is*/
		   append_char(chartbl[c2]);
  }
  else if (c1 & 0x10)		// control code / special char
  {
	  int channel= (c1 & 0x08) >> 3;
	  c1&=~0x08;
	  if(data!=lastcode)
	  {
	  	if(c2 & 0x40) {	/*PAC, Preamble Address Code */
			append_char('\n'); /*FIXME properly interpret PACs*/
		}
		else
			switch(c1)
			{
				case 0x10:	break; // ext attribute
				case 0x11: 
					if((c2 & 0x30)==0x30) 
					{
						//printf("[debug]:Special char (ignored)\n");
						/*cc_decode_special_char()*/;
					}
					else if (c2 & 0x20) 
					{
						//printf("[debug]: midrow_attr (ignored)\n");
						/*cc_decode_midrow_attr()*/;
					}
					break;
				case 0x14:
					switch(c2)
					{
						case 0x2C: display_buffer(NULL); //EDM
							   clear_buffer(fb); break;
						case 0x2d: append_char('\n');	//carriage return
							   break;
						case 0x2e: clear_buffer(bb);	//ENM
							   break;
						case 0x2f: swap_buffers();	//Swap buffers
							   display_buffer(fb);
							   clear_buffer(bb);
							   break;
					}
					break;
				case 0x17:
					if( c2>=0x21 && c2<=0x23) //TAB
					{
						break;
					}
			}
	  }
  } 
  lastcode=data;  
}

void subcc_decode()
{
  /* The first number may denote a channel number. I don't have the
   * EIA-708 standard, so it is hard to say.
   * From what I could figure out so far, the general format seems to be:
   *
   * repeat
   *
   *   0xfe starts 2 byte sequence of unknown purpose. It might denote
   *        field #2 in line 21 of the VBI. We'll ignore it for the
   *        time being.
   *
   *   0xff starts 2 byte EIA-608 sequence, field #1 in line 21 of the VBI.
   *        Followed by a 3-code triplet that starts either with 0xff or
   *        0xfe. In either case, the following triplet needs to be ignored
   *        for line 21, field 1.
   *
   *   0x00 is padding, followed by 2 more 0x00.
   *
   *   0x01 always seems to appear at the beginning, always seems to
   *        be followed by 0xf8, 8-bit number. 
   *        The lower 7 bits of this 8-bit number seem to denote the
   *        number of code triplets that follow.
   *        The most significant bit denotes whether the Line 21 field 1 
   *        captioning information is at odd or even triplet offsets from this
   *        beginning triplet. 1 denotes odd offsets, 0 denotes even offsets.
   *      
   *        Most captions are encoded with odd offsets, so this is what we
   *        will assume.
   *
   * until end of packet
   */
  unsigned char *current = inputbuffer;
  unsigned int curbytes = 0;
  unsigned char data1, data2;
  unsigned char cc_code;
  int odd_offset = 1;

  while (curbytes < inputlength) {
    int skip = 2;

    cc_code = *(current);

    if (inputlength - curbytes < 2) {
#ifdef LOG_DEBUG
      fprintf(stderr, "Not enough data for 2-byte CC encoding\n");
#endif
      break;
    }
    
    data1 = *(current+1);
    data2 = *(current + 2);
    current++; curbytes++;
    
    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 */
      // FIXME check parity!
      // Parity check omitted assuming we are reading from a DVD and therefore
      // we should encounter no "transmission errors".
      cc_decode_EIA608(data1 | (data2 << 8));
      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:
//#ifdef LOG_DEBUG
      fprintf(stderr, "Unknown CC encoding: %x\n", cc_code);
//#endif
      skip = 2;
      break;
    }
    current += skip;
    curbytes += skip;
  }
}


void subcc_process_data(unsigned char *inputdata,unsigned int len)
{
	if(!subcc_enabled) return;
	if(!inited) subcc_init();
	
	memcpy(inputbuffer,inputdata,len);
	inputlength=len;
	subcc_decode();
}


--- NEW FILE ---
#ifndef SUB_CC_H
#define SUB_CC_H

void subcc_process_data(unsigned char *inputdata,unsigned int len);

#endif /*SUB_CC_H*/


Index: mplayer.c
===================================================================
RCS file: /cvsroot/mplayer/main/mplayer.c,v
retrieving revision 1.529
retrieving revision 1.530
diff -u -r1.529 -r1.530
--- mplayer.c	24 Jul 2002 18:17:09 -0000	1.529
+++ mplayer.c	25 Jul 2002 03:37:27 -0000	1.530
@@ -261,6 +261,7 @@
 int   sub_auto = 1;
 char *vobsub_name=NULL;
 /*DSP!!char *dsp=NULL;*/
+int   subcc_enabled=0;
 
 extern char *vo_subdevice;
 extern char *ao_subdevice;

Index: mencoder.c
===================================================================
RCS file: /cvsroot/mplayer/main/mencoder.c,v
retrieving revision 1.141
retrieving revision 1.142
diff -u -r1.141 -r1.142
--- mencoder.c	21 Jul 2002 22:20:05 -0000	1.141
+++ mencoder.c	25 Jul 2002 03:37:27 -0000	1.142
@@ -171,6 +171,7 @@
 float sub_delay=0;
 float sub_fps=0;
 int   sub_auto = 0;
+int   subcc_enabled=0;
 
 #ifdef USE_SUB
 static subtitle* subtitles=NULL;

Index: cfg-common.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-common.h,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -r1.49 -r1.50
--- cfg-common.h	20 Jul 2002 13:53:40 -0000	1.49
+++ cfg-common.h	25 Jul 2002 03:37:27 -0000	1.50
@@ -156,6 +156,8 @@
 	{"noutf8", &sub_utf8, CONF_TYPE_FLAG, 0, 1, 0, NULL},
 	// specify IFO file for VOBSUB subtitle
 	{"ifo", &spudec_ifo, CONF_TYPE_STRING, 0, 0, 0, NULL},
+	// enable Closed Captioning display
+	{"subcc", &subcc_enabled, CONF_TYPE_FLAG, 0, 0, 1, NULL},
 #endif
 #ifdef USE_OSD
 	{"font", &font_name, CONF_TYPE_STRING, 0, 0, 0, NULL},

Index: Makefile
===================================================================
RCS file: /cvsroot/mplayer/main/Makefile,v
retrieving revision 1.195
retrieving revision 1.196
diff -u -r1.195 -r1.196
--- Makefile	10 Jul 2002 20:56:50 -0000	1.195
+++ Makefile	25 Jul 2002 03:37:27 -0000	1.196
@@ -31,7 +31,7 @@
 # a BSD compatible 'install' program
 INSTALL = install
 
-SRCS_COMMON = xacodec.c cpudetect.c codec-cfg.c cfgparser.c my_profile.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c find_sub.c
+SRCS_COMMON = xacodec.c cpudetect.c codec-cfg.c cfgparser.c my_profile.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c sub_cc.c find_sub.c
 SRCS_MENCODER = mencoder.c mp_msg-mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/osd.c libvo/sub.c libvo/font_load.c me-opt-reg.c
 SRCS_MPLAYER = mplayer.c mp_msg.c $(SRCS_COMMON) lirc_mp.c mixer.c mp-opt-reg.c
 




More information about the MPlayer-cvslog mailing list