📄 teletext.java
字号:
/*
* @(#)Teletext.java - constants/decode of teletext System B
*
* Copyright (c) 2001-2005 by dvb.matt, All Rights Reserved.
*
* This file is part of X, a free Java based demux utility.
* X is intended for educational purposes only, as a non-commercial test project.
* It may not be used otherwise. Most parts are only experimental.
*
*
* This program is free software; you can redistribute it free of charge
* and/or modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package net.sourceforge.dvb.projectx.subtitle;
import java.util.Hashtable;
import net.sourceforge.dvb.projectx.common.X;
public final class Teletext
{
private Teletext()
{}
private final static String[] ssaHeader = {
"[Script Info]",
"; This is a Sub Station Alpha v4 script.",
"; For Sub Station Alpha info and downloads,",
"; go to http://www.eswat.demon.co.uk/",
"; or email kotus@eswat.demon.co.uk",
"; to burn-in these subtitles into an AVI, just install subtitler2.3 PlugIn for VirtualDub, see doom9.org",
"Title: Subtitles taken from TV teletext",
"Original Script: by their respective owner",
"ScriptType: v4.00",
"Collisions: Normal",
"PlayResY: 240", // maybe replaced [10]
"PlayDepth: 0",
"Timer: 100.0000", // maybe replaced [12]
"[V4 Styles]",
"Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding",
"Style: MainB,Arial,14,&H00FFFF,&H00FFFF,&H00FFFF,0,0,-1,1,2,4,1,16,16,16,0,0",
"Style: MainT,Arial,14,&HFFFFFF,&HFFFFFF,&HFFFFFF,0,1,0,1,2,4,1,16,16,16,0,0",
"Style: MainI,Arial,14,&HFFFFFF,&HFFFFFF,&HFFFFFF,0,1,1,1,2,4,1,16,16,16,0,0", //DM30122003 081.6 int10 add
"Style: MainC,Courier New,14,&HFFFFFF,&HFFFFFF,&HFFFFFF,0,1,0,1,2,4,1,16,16,16,0,0",
"[Events]",
"Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text",
"Comment: Marked=0,0:00:00.00,0:00:00.01,MainB,,0000,0000,0000,!Effect,This script was created by decoding a tv teletext stream to build coloured subtitles"
};
private final static String[] ssaLine = {
"Dialogue: Marked=0,",
",MainT,,0000,0000,0000,!Effect,{\\q2\\a2}"
};
//DM26052004 081.7 int03 changed
private final static String[] stlHeader = {
"",
"//Font select and font size",
"$FontName = Arial",
"$FontSize = 30",
"//Character attributes (global)",
"$Bold = FALSE",
"$UnderLined = FALSE",
"$Italic = FALSE",
"//Position Control",
"$HorzAlign = Center",
"$VertAlign = Bottom",
"$XOffset = 10",
"$YOffset = 10",
"//Contrast Control",
"$TextContrast = 15",
"$Outline1Contrast = 8",
"$Outline2Contrast = 15",
"$BackgroundContrast = 0",
"//Effects Control",
"$ForceDisplay = FALSE",
"$FadeIn = 0",
"$FadeOut = 0",
"//Other Controls",
"$TapeOffset = FALSE",
"//Colors",
"$ColorIndex1 = 0",
"$ColorIndex2 = 1",
"$ColorIndex3 = 2",
"$ColorIndex4 = 3",
"//Subtitles"
};
//DM14052004 081.7 int02 add
private final static String[] sonHeader = {
"st_format\t2",
"Display_Start\tnon_forced",
"TV_Type\t\tPAL",
"Tape_Type\tNON_DROP",
"Pixel_Area\t(0 575)",
"Directory\t",
"",
"SP_NUMBER\tSTART\t\tEND\t\tFILE_NAME"
};
private final static String[] colors = {
"{\\c&HC0C0C0&}", // black /gray
"{\\c&H4040FF&}", // red
"{\\c&H00FF00&}", // green
"{\\c&H00FFFF&}", // yellow
"{\\c&HFF409B&}", // blue //DM15032004 081.6 int18 changed
"{\\c&HFF00FF&}", // magenta
"{\\c&HFFFF00&}", // cyan
"{\\c&HFFFFFF&}", // white
};
//DM14052004 081.7 int02 add
public static String[] getSONHead(String path, long frame_rate)
{
if (frame_rate != 3600)
{
sonHeader[2] = "TV_Type\t\tNTSC";
sonHeader[3] = "Tape_Type\tDROP";
}
else
{
sonHeader[2] = "TV_Type\t\tPAL";
sonHeader[3] = "Tape_Type\tNON_DROP";
}
sonHeader[5] = "Directory\t" + path;
return sonHeader;
}
/*****************
* return STL header *
*****************/
public static String[] getSTLHead(String version)
{
stlHeader[0] = "//Generated by " + version;
return stlHeader;
}
/*****************
* return SSA header *
*****************/
public static String[] getSSAHead()
{
return ssaHeader;
}
/*****************
* return SSA line *
*****************/
public static String[] getSSALine()
{
return ssaLine;
}
/*****************
* return SMPTE *
*****************/
public static String SMPTE(String time, long videoframetime)
{
StringBuffer a = new StringBuffer();
a.append(time.substring(0, 8) + ":00");
String b = "" + (Integer.parseInt(time.substring(9, 12)) / ((int)videoframetime / 90));
a.replace((b.length() == 1) ? 10 : 9 , 11, b);
return a.toString();
}
/*****************
* change endian *
*****************/
public static byte bytereverse(byte n)
{
n = (byte) (((n >> 1) & 0x55) | ((n << 1) & 0xaa));
n = (byte) (((n >> 2) & 0x33) | ((n << 2) & 0xcc));
n = (byte) (((n >> 4) & 0x0f) | ((n << 4) & 0xf0));
return n;
}
/**************
* set parity *
**************/
public static byte parity(byte n)
{
boolean par=true;
if (n == 0)
return n;
for (int a=0; a < 8; a++)
if ((n>>>a & 1) == 1)
par = !par;
if (par)
return (byte)(0x80 | n);
return n;
}
/****************
* check parity *
****************/
public static boolean cparity(byte n)
{
boolean par=true;
if (n == 0)
return true;
for (int a=0; a < 7; a++)
if ((n>>>a & 1) == 1)
par = !par;
if (par && (1 & n>>>7) == 1)
return true;
else if (!par && (1 & n>>>7) == 0)
return true;
return false;
}
//DM24052004 081.7 int03 introduced
//no error correction ATM
public static int hamming24_18(byte b[], int off)
{
int val = 0;
val |= (0xFE & b[off + 2])>>>1;
val |= (0xFE & b[off + 1])<<6;
val |= (0xE & b[off])<<13;
val |= (0x20 & b[off])<<12;
return val;
}
/******************
* hamming decode *
******************/
//DM12032004 081.6 int18 changed
//DM24052004 081.7 int03 changed
public static byte hamming_decode(byte a)
{
switch (0xFF & a)
{
case 0xa8:
return 0;
case 0x0b:
return 1;
case 0x26:
return 2;
case 0x85:
return 3;
case 0x92:
return 4;
case 0x31:
return 5;
case 0x1c:
return 6;
case 0xbf:
return 7;
case 0x40:
return 8;
case 0xe3:
return 9;
case 0xce:
return 10;
case 0x6d:
return 11;
case 0x7a:
return 12;
case 0xd9:
return 13;
case 0xf4:
return 14;
case 0x57:
return 15;
default:
return -1; // decode error , not yet corrected
}
}
/******************************
* make suppic from teletext *
******************************/
//DM30122003 081.6 int10 changed
//DM24072004 081.7 int07 changed
//DM09082004 081.7 int08 changed
public static int[] makepic(byte[] packet, int offset, int len, int row, int character_set, boolean checkParity)
{
// return int char<<8 | 0xF0 & active_color backgrnd | 0xF & active_color foregrnd
boolean ascii = true, toggle = false;
int chars[] = new int[len];
int active_color = 7; // init with white ascii color per line + black background
int primary_set_mapping = X.getForcedTTXLanguage() < 0 ? 0 : X.getForcedTTXLanguage();
int primary_national_set_mapping = character_set;
int secondary_set_mapping = primary_set_mapping;
int secondary_national_set_mapping = primary_national_set_mapping;
if (page_modifications.containsKey("primary_set"))
secondary_set_mapping = primary_set_mapping = Integer.parseInt(page_modifications.get("primary_set").toString());
if (page_modifications.containsKey("primary_national_set"))
secondary_national_set_mapping = primary_national_set_mapping = Integer.parseInt(page_modifications.get("primary_national_set").toString());
if (page_modifications.containsKey("secondary_set"))
{
secondary_set_mapping = Integer.parseInt(page_modifications.get("secondary_set").toString());
secondary_national_set_mapping = Integer.parseInt(page_modifications.get("secondary_national_set").toString());
}
active_set = CharSet.getActive_G0_Set(primary_set_mapping, primary_national_set_mapping, row);
active_national_set = CharSet.getActiveNationalSubset(primary_set_mapping, primary_national_set_mapping, row);
for (int c = offset, val, i = 0; i < len; c++, i++)
{
val = row<<16 | i;
if (page_modifications.containsKey("" + val))
{
chars[i] = active_color | (int)(page_modifications.get("" + val).toString().charAt(0))<<8;
continue;
}
if (checkParity && !cparity(packet[c]))
packet[i] = 8; //if error, switch to graphics mode (= space)
int char_value = 0x7F & bytereverse(packet[c]);
if (char_value>>>3 == 0) //0x0..7
{
ascii=true;
chars[i] = (active_set[32]<<8 | active_color);
active_color = (0xF0 & active_color) | char_value;
continue;
}
else if (char_value>>>4 == 0) //0x8..F
{
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value>>>7 == 1) //0x80..FF
{
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value < 27) //0x10..1A
{
ascii = false;
chars[i] = active_set[32]<<8 | active_color;
continue;
}
else if (char_value < 32) //0x1B..1F
{
switch (char_value) //1d=new bg with last color, 1c=black bg, 1b ESC
{
case 0x1B:
if (toggle)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -