From patchwork Sat Oct 22 12:57:28 2005 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dominique Dumont X-Patchwork-Id: 12070 Received: from smtp3-g19.free.fr ([212.27.42.29]) by www.linuxtv.org with esmtp (Exim 4.50) id 1ETIwH-00027X-2J for vdr@linuxtv.org; Sat, 22 Oct 2005 14:57:33 +0200 Received: from gandalf.hd.free.fr (wmh38-1-82-225-140-65.fbx.proxad.net [82.225.140.65]) by smtp3-g19.free.fr (Postfix) with ESMTP id 16A8837529; Sat, 22 Oct 2005 14:57:27 +0200 (CEST) Received: from domi by gandalf.hd.free.fr with local (Exim 4.54) id 1ETIwD-0005nx-77; Sat, 22 Oct 2005 14:57:29 +0200 From: Dominique Dumont To: Klaus Schmidinger's , Package Development List for Date: Sat, 22 Oct 2005 14:57:28 +0200 Message-ID: <87fyqt4slj.fsf@gandalf.hd.free.fr> User-Agent: Gnus/5.110004 (No Gnus v0.4) Emacs/21.4 (gnu/linux) MIME-Version: 1.0 X-SA-Exim-Connect-IP: X-SA-Exim-Mail-From: domi.dumont@free.fr X-SA-Exim-Scanned: No (on gandalf.hd.free.fr); SAEximRunCond expanded to false Subject: [vdr] [PATCH] for ttxtsubs plugin to use esyslog instead of fprintf X-BeenThere: vdr@linuxtv.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Klaus Schmidinger's VDR List-Id: Klaus Schmidinger's VDR List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Oct 2005 12:57:33 -0000 Status: O X-Status: X-Keywords: X-UID: 5606 Hello To be able to debug ttxtsubs plugin with a vdr daemon, I had to modify ttxtsubs plugin to change the fprintf(stderr,...) calls to esyslog calls. I've made debian patches (dpatch styles), but they are usable for non-debian environment. The first patch add some "#include " The second patch is actually a dpatch, i.e. a small perl script that replaces fprintf with esyslog. This script accepts -patch and -unpatch arguments so the modif can be reversed. (I've written a script so the dpatch will be smaller and more resilient to upstream changes) Feel free to use it for debian project or any other vdr related project. Cheers #! /bin/sh /usr/share/dpatch/dpatch-run ## 95_include_vdr_tools.dpatch by ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: No description. @DPATCH@ #!/usr/bin/perl ## 96_use_syslog.dpatch -- domi.dumont@free.fr ## DP: perl script to replace fprintf with esyslog calls ## DP: (c) Dominique Dumont. Released under GPLv2 or later version. use strict ; my $action = shift @ARGV || die "Expected -patch or -unpatch option" ; my $working_dir = shift @ARGV || ''; $working_dir .= '/' unless $working_dir eq '' ; my @files = glob( $working_dir.'*.[hc]' ) ; my $to_esyslog = sub { $_[0] =~ s/fprintf\s*\(\s*stderr\s*,/esyslog\(/ ;} ; my $to_fprintf = sub { $_[0] =~ s/esyslog\s*\(/fprintf\(stderr,/ ;} ; my $replace = $action eq '-patch' ? $to_esyslog : $action eq '-unpatch' ? $to_fprintf : die "Expected -patch or -unpatch option, not $action" ; foreach my $c_file (@files) { my $nb_of_modified_lines ; open(FIN, $c_file) || die "Can't open $c_file:$!" ; my @lines = ; close FIN ; $nb_of_modified_lines = scalar grep { $replace->($_) } @lines ; next unless $nb_of_modified_lines ; print "patched $nb_of_modified_lines lines in $c_file\n"; open(FOUT, ">$c_file") || die "Can't open $c_file to write:$!" ; print FOUT @lines ; close FOUT; } diff -urNad vdr-plugin-ttxtsubs-0.0.5~/teletext.c vdr-plugin-ttxtsubs-0.0.5/teletext.c --- vdr-plugin-ttxtsubs-0.0.5~/teletext.c 2004-03-01 23:53:17.000000000 +0100 +++ vdr-plugin-ttxtsubs-0.0.5/teletext.c 2005-10-22 14:37:14.000000000 +0200 @@ -12,6 +12,7 @@ //#include //#include +#include #include "teletext.h" #include "teletext-tables.h" diff -urNad vdr-plugin-ttxtsubs-0.0.5~/teletext.c~ vdr-plugin-ttxtsubs-0.0.5/teletext.c~ --- vdr-plugin-ttxtsubs-0.0.5~/teletext.c~ 1970-01-01 01:00:00.000000000 +0100 +++ vdr-plugin-ttxtsubs-0.0.5/teletext.c~ 2004-03-01 23:53:17.000000000 +0100 @@ -0,0 +1,724 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include + +#include "teletext.h" +#include "teletext-tables.h" +#include "teletext-chars.h" +#include "utils.h" + + +// FROM vbidecode +// unham 2 bytes into 1, report 2 bit errors but ignore them +unsigned char unham(unsigned char a,unsigned char b) +{ + unsigned char c1,c2; + + c1=unhamtab[a]; + c2=unhamtab[b]; +// if ((c1|c2)&0x40) +// fprintf(stderr,"bad ham!"); + return (c2<<4)|(0x0f&c1); +} + + +// ham 8/4 the byte in into two bytes pointed to by out +// should make a table instead +void ham8_4byte(uint8_t in, uint8_t *out) +{ + out[0] = ham8_4nibble(in & 0xF); + out[1] = ham8_4nibble(in >> 4); + + if (1) { // XXX debug + int a; + if(unham(out[0], out[1]) != in) { + fprintf(stderr, "ham8_4: 1 - result not correct %02x -> %02x %02x!\n", in, out[0], out[1]); + } + a = unhamtab[out[0]]; + a ^= 0x80; + if(a & 0xf0 || (a != (in & 0xF))) { + fprintf(stderr, "ham8_4: 2 - result not correct %02x -> %02x %02x, %02x!\n", in, out[0], out[1], a); + } + a = unhamtab[out[1]]; + a ^= 0x80; + if(a & 0xf0 || (a != (in >> 4))) { + fprintf(stderr, "ham8_4: 3 - result not correct %02x -> %02x %02x, %02x!\n", in, out[0], out[1], a); + } + } +} + +// should be a table instead +int parity(uint8_t x) { + int res = 1; + int count = x & 0xf0 ? 8 : 4; + + while(count--) { + if(x & 0x01) + res = !res; + x >>= 1; + } + + return res; +} + +// ham 8/4 the nibble in into the byte pointed to by out +// should make a table instead +// D4 P4 D3 P3 D2 P2 D1 P1 +// P4 = all the rest +uint8_t ham8_4nibble(uint8_t in) +{ + uint8_t o = 0; + + // insert the data bits + o |= (in << 4) & 0x80; + o |= (in << 3) & 0x20; + o |= (in << 2) & 0x08; + o |= (in << 1) & 0x02; + + if(parity(in & 0x0d)) // P1 = 1 . D1 . D3 . D4 + o |= 0x01; + if(parity(in & 0x0b)) // P2 = 1 . D1 . D2 . D4 + o |= 0x04; + if(parity(in & 0x07)) // P3 = 1 . D1 . D2 . D3 + o |= 0x10; + if(parity(o & 0xbf)) // P4 = 1 . P1 . D1 . ... . D3 . D4 + o |= 0x40; + + return o; +} + + +/* + * Map Latin G0 teletext characters into a ISO-8859-1 approximation. + * Trying to use similar looking or similar meaning characters. + * Gtriplet - 4 bits = triplet-1 bits 14-11 (14-8) of a X/28 or M/29 packet, if unknown - use 0 + * natopts - 3 bits = national_options field of a Y/0 packet (or triplet-1 bits 10-8 as above?) + * inchar - 7 bits = characted to remap + * Also strips parity + */ + +uint8_t ttxt_laG0_la1_char(int Gtriplet, int natopts, uint8_t inchar) +{ + int no = laG0_nat_opts_lookup[Gtriplet & 0xf][natopts & 0x7]; + uint8_t c = inchar & 0x7f; + + //dprint("\n%x/%c/%x/%x\n", c, c, laG0_nat_replace_map[c], laG0_nat_opts[no][laG0_nat_replace_map[c]]); + + if(!laG0_nat_replace_map[c]) + return c; + else + return laG0_nat_opts[no][laG0_nat_replace_map[c]]; +} + +/* + * Map Latin G2 teletext characters into a ISO-8859-1 approximation. + * Trying to use similar looking or similar meaning characters. + */ +uint8_t ttxt_laG2_la1_char(uint8_t inchar) +{ + return laG2_la1_table[inchar & 0x7f]; +} + +void dump_hex(char *msg, const uint8_t *p, int len) +{ + int i; + printf("%s:", msg); + for(i = 0; i < len; i++) { + printf(" %02x", p[i]); + } + printf("\n"); +} + + +void +print_code(uint8_t c, int natopts) +{ + if(c >= 0x20) { + dprint("%c", ttxt_laG0_la1_char(0, natopts, c)); + } else + switch(c) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + dprint("", c); + break; + case 0x08: + dprint(""); + break; + case 0x09: + dprint(""); + break; + case 0x0a: + dprint("]"); + break; + case 0x0b: + dprint("["); + break; + case 0x0c: + dprint(""); + break; + case 0x0d: + dprint(""); + break; + case 0x0e: + dprint(""); + break; + case 0x0f: + dprint(""); + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + dprint("", c-0x10); + break; + case 0x18: + dprint(""); + break; + case 0x19: + dprint(""); + break; + case 0x1a: + dprint(""); + break; + case 0x1b: + dprint(""); + break; + case 0x1c: + dprint(""); + break; + case 0x1d: + dprint(""); + break; + case 0x1e: + dprint(""); + break; + case 0x1f: + dprint(""); + break; + default: + dprint("", c); + } +} + +void +print_page(struct ttxt_page *p) +{ + int r, c, e; + + dprint("\n\n%03x %s%s%s%s%snatchars: %d\n", + (p->mag << 8) + p->no, + p->flags & erasepage ? "erasepage, " : "", + p->flags & newsflash ? "Newsflash, " : "", + p->flags & subtitle ? "Subtitle, " : "", + p->flags & suppress_header ? "SuppressHeader, " : "", + p->flags & inhibit_display ? "InihinitDisplay, " : "", + p->national_charset); + + for(r = 0; r < 26; r++) { + int do_display = 0; + + for(e = 39; e > 0; e--) { + if(p->data[r][e]) { + do_display = 1; + break; + } + } + + if(do_display) { + dprint("%02d ", r); + for(c = 0; c <= e; c++) { + char z = p->data[r][c] & 0x7f; + print_code(z, p->national_charset); + //dprint("%c", isprint(z) ? z : z == 0 ? '\'' : '.'); + } + dprint("\n"); + } + } +} + + +void print_line(char *p) +{ + int mp; + int mag; // X in ETSI EN 300 706 + int packet; // Y + struct ttxt_data_field *d = (struct ttxt_data_field *) p; + + mp = unham(invtab[d->mag_addr_ham[0]], invtab[d->mag_addr_ham[1]]); + mag = mp & 0x7; + packet = (mp >> 3) & 0x1f; + + dprint("I%d Y%02d M%d ", d->data_unit_id, packet, mag); + + // packet 0, change page no in this magazine + if(packet == 0) { + int no; + uint8_t buf[8]; + + for(int i = 0; i < 8; i++) + buf[i] = invtab[d->data[i]]; + + no = unham(buf[0], buf[1]); + + dprint("P%02x ", no); + + dprint("<"); + for(int i = 8; i < 40; i++) + print_code(invtab[d->data[i]] & 0x7f, 0); + dprint(">"); + + if(buf[3] & 0x80) dprint(", erase page"); + if(buf[5] & 0x20) dprint(", newsflash"); + if(buf[5] & 0x80) dprint(", subtitle"); + if(buf[6] & 0x02) dprint(", suppress header"); + if(buf[6] & 0x08) dprint(", update indicator"); + if(buf[6] & 0x20) dprint(", interrupted sequence"); + if(buf[6] & 0x80) dprint(", inhibit display"); + if(buf[7] & 0x02) dprint(", magazine serial"); + + dprint(", charset=%d", ((buf[7] & 0x80) >> 5) + ((buf[7] & 0x20) >> 4) + ((buf[7] & 0x08) >> 3)); + } else { + dprint("<"); + for(int i = 0; i < 40; i++) + print_code(invtab[d->data[i]] & 0x7f, 0); + dprint(">"); + } + + dprint("\n"); +} + + +#if 0 +void +show_page(struct ttxt_page *p) +{ + static cOsdBase *o = NULL; + static tWindowHandle w1 = 0; + static tWindowHandle w2 = 0; + static int open1 = 0, open2 = 0; + char *s1 = NULL, *s2 = NULL; + int i, j; + + for(i = 1; i < TTXT_ROWS; i++) { + char *s = NULL; + if(p->data[i][0]) { + int do_incr = 0; + dprint("Checking row %d\n", i); + for(j = 0; j < 40; j++) { + p->data[i][j] = p->data[i][j] & 0x7f; + switch(p->data[i][j]) { + case 0x0d: // double height + case 0x0f: // double size + do_incr = 1; + break; + case 0x0a: // box end + p->data[i][j] = '\0'; + break; + case 0x0b: // box begin + s = (char *) &(p->data[i][j+1]); + dprint("Using row %d\n", i); + break; + case '[': + p->data[i][j] = 'Ä'; + break; + case ']': + p->data[i][j] = 'Å'; + break; + case '\\': + p->data[i][j] = 'Ö'; + break; + case '{': + p->data[i][j] = 'ä'; + break; + case '}': + p->data[i][j] = 'å'; + break; + case '|': + p->data[i][j] = 'ö'; + break; + } + } + if(do_incr) + i++; + dprint("\n"); + } + + if(s) + if(!s1) + s1 = s; + else if(!s2) + s2 = s; + } + + if(s1 && !s2) { + s2 = s1; + s1 = NULL; + } + + if(s1) + dprint("S1: %s\n", s1); + else + dprint("S1: \n"); + if(s2) + dprint("S2: %s\n", s2); + else + dprint("S2: \n"); + + if(o != NULL) { + if(open1) { + o->Clear(w1); + open1 = 0; + } + if(open2) { + o->Clear(w2); + open2 = 0; + } + + o->Clear(); + delete o; + o = NULL; + } + + if(!s1 && !s2) + return; + + o = cOsd::OpenRaw(125, 450); + + if(o == NULL) + return; + + o->SetFont(fontOsd); + + if(s1) { + int w = o->Width((char *) s1); + dprint("w1: %d\n", w); + w = 450; + int h = 36; + w1 = o->Create(0, 0, w, h, 2); +#if 0 + o->AddColor(clrBackground, w1); + o->AddColor(clrWhite, w1); +#endif + o->Fill(0, 0, w, h, clrBackground, w1); + o->Text(15, 4, (char *) s1, clrWhite, clrBackground, w1); + open1 = 1; + } + + if(s2) { + int w = o->Width((char *) s2); + dprint("w2: %d\n", w); + w = 452; + int h = 36; + w2 = o->Create(0, 45, w, h, 2); +#if 0 + o->AddColor(clrBackground, w2); + o->AddColor(clrWhite, w2); +#endif + o->Fill(0, 45, w, 45 + h, clrBackground, w2); + o->Text(15, 45 + 4, (char *) s2, clrWhite, clrBackground, w2); + open2 = 1; + } + + o->Flush(); +} +#endif + +#if 0 +void +ttxt_packet_in(int data_unit_id, int mag, int pack, uint8_t *data) +{ + static int valid = 0; + static struct ttxt_page p; + int i; + + if(pack == 0) { + if(valid) + if(p.mag == TTXT_MAG && p.no == TTXT_PAGE) + if(p.subtitle) + //print_page(&p); + /* if(p.mag == 1) */{ + show_page(&p); + print_page(&p); + } + + memset(&p, 0, sizeof(p)); + p.data_unit_id = data_unit_id; + p.mag = mag; + p.no = unham(data[0], data[1]); + + if(data[3] & 0x80) { // Erase Page + memset(p.data, 0, sizeof(p.data)); + p.erasepage = 1; + } + if(data[5] & 0x20) // Newsflash + p.newsflash = 1; + if(data[5] & 0x80) // Subtitle + p.subtitle = 1; + if(data[6] & 0x02) // Suppress Header + p.suppress_header = 1; + //if(data[6] & 0x08) // Update Indicator + //if(data[6] & 0x20) // Interrupted Sequence + if(data[6] & 0x80) // Inhibit Display + p.inhibit_display = 1; + //if(data[7] & 0x02) // Magazine Serial + + p.national_charset = + ((data[7] & 0x80) >> 7) + ((data[7] & 0x20) >> 4) + ((data[7] & 0x08) >> 1); + + valid = 1; + + for(i = 0; i < 32; i++) + p.data[0][i] = data[i+8]; + } else if(pack < 26) { + for(i = 0; i < 42; i++) + p.data[pack][i] = data[i]; + } else { + if((valid && p.mag == TTXT_MAG && p.no == TTXT_PAGE) || + pack == 28) + dprint("mag: %d, pack: %d, page: %02x\n", p.mag, pack, p.no); + } +} +#endif + +#if 0 +void +ttxt_pes_data_in(struct ttxt_pes_data_field *t, int len) +{ + int i; + + if(len < 1) + return; + + if(t->data_identifier < 0x10 || t->data_identifier > 0x1F) { + dprint("Unknown data identifier: %02x\n", t->data_identifier); + return; + } + + for(i = 0; (uint8_t *) (&(t->d[i+1])) < (((uint8_t *) t) + len); i++) { + struct ttxt_data_field *d = &(t->d[i]); + int i; + uint8_t *p; + int uh; + int mag; + int pack; + + // if(d->data_unit_id != ttxt_subtitle) + // continue; + + p = (uint8_t *) &(d->mag_addr_ham); + for(i = 0; i < 42; i++) { + p[i] = invtab[p[i]]; + } + + uh = unham(d->mag_addr_ham[0], d->mag_addr_ham[1]); + mag = uh & 0x7; + pack = (uh >> 3) & 0x1f; + + // dump_hex("line", (uint8_t *) d, 20); + // dprint("id: %d, line: %d, mag %d, pack: %d\n", d->data_unit_id, TTXT_LINE_NO(*d), mag, pack); + + ttxt_packet_in(d->data_unit_id, mag, pack, d->data); + } +} + + +void +set_filt(int fd,uint16_t tt_pid, dmx_pes_type_t t) +{ + struct dmx_pes_filter_params pesFilterParams; + + memset(&pesFilterParams, 0, sizeof(pesFilterParams)); + + pesFilterParams.pid = tt_pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TAP; + pesFilterParams.pes_type = t; + pesFilterParams.flags = DMX_IMMEDIATE_START; + + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) + perror("DMX SET PES FILTER:"); + + // XXX set buffer size too? +} +#endif + +#if 0 +#define BUFSIZE 2000 + +// external entry point +void ttxt_decode(int fd, int tpid, int *doRun) +{ + uint8_t buf[BUFSIZE]; + int n; + int hunt = 1; + + set_filt(fd, tpid, DMX_PES_OTHER); + + while (*doRun) { + restart: + if(hunt) { + int i; + + dprint("hunting...\n"); + n = read(fd, buf, 199); + if(n < 0) { + perror("ttxt_decode:read: "); + goto restart; + } + + for(i = 0; i < (n - 3); i++) { + if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 1 && buf[i+3] == 0xbd) { + struct ttxt_pes_header *p = (struct ttxt_pes_header *) (buf + i); + size_t skip = ntohs(p->len) + 6 - (n - i); + + if(skip > 0) { + read(fd, buf, skip < sizeof(buf) ? skip : sizeof(buf)); + if(n < 0) { + perror("ttxt_decode:read: "); + goto restart; + } + hunt = 0; + break; + } + } + } + } else { + struct ttxt_pes_header *p = (struct ttxt_pes_header *) buf; + + n = read(fd, buf, 6); + if(n < 0) { + perror("ttxt_decode:read: "); + goto restart; + } + + if(p->start[0] != 0 || p->start[1] != 0 || p->start[2] != 1 || + p->stream_id != 0xbd || // private_stream_1 + ntohs(p->len) > (sizeof(buf) - 6)) { + dprint("Lost PES packet sync, hunting...\n"); + hunt = 1; + continue; + } + + n = read(fd, buf + 6, ntohs(p->len)); + if(n < 0) { + perror("ttxt_decode:read: "); + goto restart; + } + + // dprint("len: %d\n", n); + + if(n != ntohs(p->len) || + p->header_len != 0x24) { // header should allways be 0x24 long (EN 300 472) + dprint("Error reading PES packet, hunting...\n"); + hunt = 1; + continue; + } + + ttxt_pes_data_in((struct ttxt_pes_data_field *) (buf + 45), n + 6 - 45); + } + + // fwrite(buf,1,n,stdout); + } + + dprint("ttxt_decode DONE!\n"); +} +#endif + + +#if 0 +int +main(int argc, char **argv) +{ + int fd; + int pid; + uint8_t buf[BUFSIZE]; + int n; + int hunt = 1; + + if (argc!=2) { + fprintf(stderr,"USAGE: %s PID\n", argv[0]); + return -1; + } + + pid = atoi(argv[1]); + + if((fd = open("/dev/dvb/adapter0/demux0", O_RDWR)) < 0){ + perror("Error opening demux device: "); + return -1; + } + + set_filt(fd, pid, DMX_PES_OTHER); + + for (;;) { + if(hunt) { + int i; + + dprint("hunting...\n"); + n = read(fd, buf, 199); + + for(i = 0; i < (n - 3); i++) { + if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 1 && buf[i+3] == 0xbd) { + struct ttxt_pes_header *p = (struct ttxt_pes_header *) (buf + i); + int skip = ntohs(p->len) + 6 - (n - i); + + if(skip > 0) { + read(fd, buf, skip < sizeof(buf) ? skip : sizeof(buf)); + hunt = 0; + break; + } + } + } + } else { + struct ttxt_pes_header *p = (struct ttxt_pes_header *) buf; + + n = read(fd, buf, 6); + + if(p->start[0] != 0 || p->start[1] != 0 || p->start[2] != 1 || + p->stream_id != 0xbd || // private_stream_1 + ntohs(p->len) > (sizeof(buf) - 6)) { + dprint("Lost PES packet sync, hunting...\n"); + hunt = 1; + continue; + } + + n = read(fd, buf + 6, ntohs(p->len)); + + // dprint("len: %d\n", n); + + if(n != ntohs(p->len) || + p->header_len != 0x24) { // header should allways be 0x24 long (EN 300 472) + dprint("Error reading PES packet, hunting...\n"); + hunt = 1; + continue; + } + + ttxt_pes_data_in((struct ttxt_pes_data_field *) (buf + 45), n + 6 - 45); + } + + // fwrite(buf,1,n,stdout); + } + + return 0; +} +#endif diff -urNad vdr-plugin-ttxtsubs-0.0.5~/ttxtsubsfilter.c vdr-plugin-ttxtsubs-0.0.5/ttxtsubsfilter.c --- vdr-plugin-ttxtsubs-0.0.5~/ttxtsubsfilter.c 2004-03-01 23:53:17.000000000 +0100 +++ vdr-plugin-ttxtsubs-0.0.5/ttxtsubsfilter.c 2005-10-22 14:37:38.000000000 +0200 @@ -4,6 +4,8 @@ #include #include +#include + #include "ttxtsubsfilter.h" #include "teletext.h" diff -urNad vdr-plugin-ttxtsubs-0.0.5~/ttxtsubsfilter.c~ vdr-plugin-ttxtsubs-0.0.5/ttxtsubsfilter.c~ --- vdr-plugin-ttxtsubs-0.0.5~/ttxtsubsfilter.c~ 1970-01-01 01:00:00.000000000 +0100 +++ vdr-plugin-ttxtsubs-0.0.5/ttxtsubsfilter.c~ 2004-03-01 23:53:17.000000000 +0100 @@ -0,0 +1,162 @@ + +#include +#include +#include +#include + +#include "ttxtsubsfilter.h" +#include "teletext.h" + +cTtxtSubsFilter::cTtxtSubsFilter(void) + : + mCount(0), + mPages(0) +{ + int i; + for(i = 0; i < 8; i++) + mMagPage[i] = -1; +} + + +cTtxtSubsFilter::~cTtxtSubsFilter(void) +{ + FreePages(); +} + + +void cTtxtSubsFilter::SetPages(size_t count, uint16_t *pages) +{ + FreePages(); + + mPages = (uint16_t *) malloc(count * sizeof(uint16_t)); + + memcpy((char *) mPages, (char *) pages, count * sizeof(uint16_t)); + + mCount = count; + + if(0) { + fprintf(stderr, "SetPages: %d, ", count); + for(size_t i = 0; i < count; i++) + fprintf(stderr, "%03x ", pages[i]); + fprintf(stderr, "\n"); + } +} + +// XXX IF MERGING PAGES FROM SEVERAL PIDS (which we currently don't) +// Need to insert a line Y0 if +// - there has been data from other streams inserted and the next line is not a Y0 +// there has been data from other magazines and the next line for this mag is not a Y0 +// indata and outdata are pointers to a ttxt data row buffers, +// if return value <> 0 outdata countains data to pass on +int cTtxtSubsFilter::Filter(char *indata, char *outdata) +{ + int mp; + int mag; // X in ETSI EN 300 706 + int packet; // Y + int result = 0; + + struct ttxt_data_field *d = (struct ttxt_data_field *) indata; + + mp = UNHAM_INV(d->mag_addr_ham[0], d->mag_addr_ham[1]); + mag = mp & 0x7; + packet = (mp >> 3) & 0x1f; + + if (0) { // XXX + uint8_t buf[2]; + ham8_4byte(mp, buf); + fprintf(stderr, "unham %02x %02x -> %02x, ham: %02x %02x\n", + invtab[d->mag_addr_ham[0]], invtab[d->mag_addr_ham[1]], + mp, + buf[0], buf[1]); + } + + // packet 0, change page no in this magazine + if(packet == 0) { + uint8_t no; + int newindex; + + no = UNHAM_INV(d->data[0], d->data[1]); + + mMagPage[mag] = newindex = Find(mCount, mPages, (mag << 8) | no); + + if(newindex != -1) { + //fprintf(stderr, "Filter: %x%02x (%d)\n", mag, no, newindex); // XXX + + MakeY0(outdata, indata, mPages[newindex]); + result = 1; + } + } else if(packet >= 1 && packet <= 25) { + if(mMagPage[mag] != -1) { + memcpy(outdata, indata, sizeof(ttxt_data_field)); + result = 1; + } + } + + return result; +} + + +void cTtxtSubsFilter::FreePages(void) +{ + mCount = 0; + + if(mPages) { + free(mPages); + mPages = NULL; + } +} + + +int cTtxtSubsFilter::Find(int count, uint16_t *pages, uint16_t pageno){ + + int i; + for(i = 0; i < count; i++) { + if(pages[i] == pageno) + return i; + } + + return -1; +} + + +// make a new Y0 line with the flags in +void cTtxtSubsFilter::MakeY0(char *outdata, char *indata, uint16_t newpageno) +{ + struct ttxt_data_field *i = (struct ttxt_data_field *) indata; + struct ttxt_data_field *o = (struct ttxt_data_field *) outdata; + uint8_t hambuf[2]; + + o->data_unit_id = 3; // EBU Teletxt subtitle data + o->data_unit_length = 44; + o->par_loff = 0xc0; // reserved bits + unknown line + o->framing_code = 0xe4; + + // new magazine number (Y = 0) + ham8_4byte((newpageno >> 8) & 0x7, hambuf); + o->mag_addr_ham[0] = invtab[hambuf[0]]; + o->mag_addr_ham[1] = invtab[hambuf[1]]; + + // new page number + ham8_4byte(newpageno & 0xff, hambuf); + o->data[0] = invtab[hambuf[0]]; + o->data[1] = invtab[hambuf[1]]; + + // copy flags + memcpy(o->data + 2, i->data + 2, 6); + + // new text + unsigned char txtbuf[32]; + size_t txtlen; + size_t n; + + txtlen = snprintf((char *) txtbuf, 32, "%03x", newpageno < 0x100 ? newpageno + 0x800 : newpageno); + + for(n = 0; n < txtlen; n++) { + if(parity(txtbuf[n])) + o->data[n + 8] = invtab[txtbuf[n] | 0x80]; // XXX wrong parity? + else + o->data[n + 8] = invtab[txtbuf[n]]; // XXX wrong parity? + } + for(; n < 32; n++) + o->data[n + 8] = invtab[(unsigned char) ' ']; // space already has right parity +}