Commit d9a4d884 authored by ogg.k.ogg.k's avatar ogg.k.ogg.k
Browse files

add a menu for subtitles selection, and a little icon when the video

 being played has subtitles available
parent cd60eea8
......@@ -196,6 +196,9 @@ parameters:
showSpeaker: boolean
Show a speaker icon when audio is available (default true)
showSubtitles: boolean
Show a subtitles icon when subtitles are available (default true)
hideTimeout: int
Timeout in seconds to hide the status area when showStatus is
auto. This timeout is to make sure that the status area is visible
......
......@@ -38,6 +38,7 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
private String kateLanguage;
private String kateCategory;
private boolean showSpeaker;
private boolean showSubtitles;
private boolean keepAspect;
private boolean ignoreAspect;
private boolean autoPlay;
......@@ -80,7 +81,7 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
public boolean paused;
public String src;
private PopupMenu menu;
private PopupMenu menu, subtitlesMenu;
private Hashtable params = new Hashtable();
private Configure configure;
private Dimension appletDimension;
......@@ -113,6 +114,7 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
{"hideTimeout", "int", "Timeout in seconds to hide the status area when " +
"showStatus is auto (default 0)"},
{"showSpeaker", "boolean", "Show a speaker icon when audio is available (default true)"},
{"showSubtitles", "boolean", "Show a subtitles icon when subtitles are available (default true)"},
{"keepAspect", "boolean",
"Use aspect ratio of video (default true)"},
{"ignoreAspect", "boolean",
......@@ -240,6 +242,7 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
showStatus = getEnumParam("showStatus", showStatusVals, "auto");
hideTimeout = getIntParam("hideTimeout", 3);
showSpeaker = getBoolParam("showSpeaker", true);
showSubtitles = getBoolParam("showSubtitles", true);
keepAspect = getBoolParam("keepAspect", true);
ignoreAspect = getBoolParam("ignoreAspect", false);
bufferSize = getIntParam("bufferSize", 200);
......@@ -293,7 +296,9 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
status = new Status(this);
status.setShowSpeaker(showSpeaker);
status.setShowSubtitles(showSubtitles);
status.setHaveAudio(audio);
status.setHaveSubtitles(false); // by default
status.setHavePercent(true);
/* assume live stream unless specified */
if (live == BOOL_FALSE) {
......@@ -332,10 +337,78 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
status.setVisible(false);
}
createMenu();
}
public void createMenu() {
subtitlesMenu = new PopupMenu("Subtitles");
subtitlesMenu.addActionListener(this);
menu = new PopupMenu();
menu.add(subtitlesMenu);
menu.addSeparator();
menu.add("About...");
menu.addActionListener(this);
this.add(menu);
populateMenu();
}
public String getCategoryName(String code) {
String names[]={
"CC", "closed captions",
"SUB", "subtitles",
"TAD", "text audio descriptions",
"KTV", "karaoke",
"TIK", "ticker text",
"AR", "active regions",
"NB", "semantic annotations",
"META","metadata",
"TRX", "transcript",
"LRC", "lyrics",
"LIN", "linguistic markup",
"CUE", "cue points",
"subtitles", "subtitles",
"spu-subtitles", "subtitles (images)",
"lyrics", "lyrics",
"K-SPU", "subtitles (images)",
};
for (int n=0;n<names.length;n+=2) if (names[n].equals(code)) return names[n+1];
return "\""+code+"\"";
}
public Locale getLocale(String rfc3066) {
rfc3066 = rfc3066.replace('-','_');
int sep = rfc3066.indexOf("_");
if (sep >= 0) {
String language = rfc3066.substring(0, sep);
String country = rfc3066.substring(sep+1);
return new Locale(language, country);
}
else {
return new Locale(rfc3066);
}
}
public void populateMenu() {
subtitlesMenu.removeAll();
int nstreams = pipeline.getNumKateStreams();
if (nstreams > 0) {
subtitlesMenu.enable();
subtitlesMenu.add("Off");
subtitlesMenu.addSeparator();
for (int n=0; n<nstreams; ++n) {
Locale locale = getLocale(pipeline.getKateStreamLanguage(n));
String displayLanguage = locale.getDisplayLanguage();
String displayCountry = locale.getDisplayCountry();
String displayLC = displayLanguage;
if (displayCountry!= null && !displayCountry.equals("")) displayLC += " ("+displayCountry+")";
String label = (n+1) + " - " + displayLC+" "+getCategoryName(pipeline.getKateStreamCategory(n));
subtitlesMenu.add(label);
}
}
else subtitlesMenu.disable();
}
public void actionPerformed(ActionEvent e) {
......@@ -345,6 +418,27 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
AboutFrame about = new AboutFrame(pipeline);
about.d.setVisible(true);
}
else if (command.equals("Off")) {
Debug.log(Debug.WARNING, "Switching subtitles off");
setParam("kateIndex","-1");
setParam("kateLanguage","");
setParam("kateCategory","");
pipeline.enableKateStream(-1, "", "");
}
else {
int idx = Integer.valueOf(command.substring(0, command.indexOf(" "))).intValue();
if (idx >= 1 && idx <= pipeline.getNumKateStreams()) {
String sidx = new String(""+(idx-1));
Debug.log(Debug.WARNING, "Switching to subtitles stream "+sidx);
setParam("kateIndex",sidx);
setParam("kateLanguage","");
setParam("kateCategory","");
pipeline.enableKateStream(idx+1, "", "");
}
else {
Debug.log(Debug.WARNING, "Failed to parse subtitle selection command string: "+command);
}
}
}
public Graphics getGraphics() {
......@@ -531,6 +625,7 @@ public class Cortado extends Applet implements Runnable, MouseMotionListener,
((MouseListener) status).mousePressed(e);
} else {
if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) {
populateMenu();
menu.show(this, e.getX(), e.getY());
}
}
......
......@@ -256,6 +256,8 @@ public class CortadoPipeline extends Pipeline implements PadListener, CapsListen
}
kselector.setState (PAUSE);
((Cortado)component).status.setHaveSubtitles(true);
}
tmp_katesink = kselector;
......@@ -806,4 +808,16 @@ public class CortadoPipeline extends Pipeline implements PadListener, CapsListen
}
return result;
}
protected int getNumKateStreams() {
return katedec.size();
}
protected String getKateStreamCategory(int idx) {
if (idx < 0 || idx >= katedec.size()) return "";
return String.valueOf(((Element)katedec.elementAt(idx)).getProperty("category"));
}
protected String getKateStreamLanguage(int idx) {
if (idx < 0 || idx >= katedec.size()) return "";
return String.valueOf(((Element)katedec.elementAt(idx)).getProperty("language"));
}
}
......@@ -39,10 +39,12 @@ public class Status extends Component implements MouseListener,
private Font font = new Font("SansSerif", Font.PLAIN, 10);
private boolean haveAudio;
private boolean haveSubtitles;
private boolean havePercent;
private boolean seekable;
private boolean live;
private boolean showSpeaker;
private boolean showSubtitles;
private boolean clearedScreen;
private static final int NONE = 0;
......@@ -58,6 +60,8 @@ public class Status extends Component implements MouseListener,
private static final int SPEAKER_WIDTH = 12;
private static final int SPEAKER_HEIGHT = 10;
private static final int SUBTITLES_WIDTH = 12;
private static final int SUBTITLES_HEIGHT = 10;
private static final int TIME_WIDTH = 38;
private static final int SEEK_TIME_GAP = 10;
private static final int THUMB_WIDTH = 9;
......@@ -85,19 +89,41 @@ public class Status extends Component implements MouseListener,
private Image speakerImg;
private int speakerWidth; // width of the speaker icon or zero if hidden
private String subtitles =
"\0\0\0\0\0\377\377\377\377\377\0\0"
+"\0\0\0\0\377\0\0\0\0\0\377\0"
+"\0\0\0\377\0\0\0\0\0\0\0\377"
+"\0\0\0\377\0\377\377\377\377\377\0\377"
+"\0\0\0\377\0\0\0\0\0\0\0\377"
+"\0\0\377\377\0\377\377\377\377\377\0\377"
+"\0\377\377\0\0\0\0\0\0\0\0\377"
+"\0\377\0\377\377\0\0\0\0\0\377\0"
+"\0\377\377\377\0\377\377\377\377\377\0\0"
+"\377\0\0\0\0\0\0\0\0\0\0\0";
private Image subtitlesImg;
private int subtitlesWidth; // width of the subtitles icon or zero if hidden
private Vector listeners = new Vector();
public Image createImage(Component comp, String s, int w, int h) {
int[] pixels = new int[w * h];
for (int i = 0; i < w * h; i++) {
pixels[i] = 0xff000000 | (s.charAt(i) << 16)
| (s.charAt(i) << 8) | (s.charAt(i));
}
return comp.getToolkit().createImage(
new MemoryImageSource(w, h, pixels, 0, w));
}
public Status(Component comp) {
int[] pixels = new int[SPEAKER_WIDTH * SPEAKER_HEIGHT];
component = comp;
for (int i = 0; i < SPEAKER_WIDTH * SPEAKER_HEIGHT; i++) {
pixels[i] = 0xff000000 | (speaker.charAt(i) << 16)
| (speaker.charAt(i) << 8) | (speaker.charAt(i));
}
speakerImg = comp.getToolkit().createImage(
new MemoryImageSource(SPEAKER_WIDTH, SPEAKER_HEIGHT, pixels, 0, SPEAKER_WIDTH));
speakerImg = createImage(comp, speaker, SPEAKER_WIDTH, SPEAKER_HEIGHT);
subtitlesImg = createImage(comp, subtitles, SUBTITLES_WIDTH, SUBTITLES_HEIGHT);
button1Color = Color.black;
button2Color = Color.black;
seekColor = Color.black;
......@@ -137,7 +163,8 @@ public class Status extends Component implements MouseListener,
private void paintPercent(Graphics g) {
if (havePercent) {
g.setColor(Color.white);
g.drawString("" + bufferPercent + "%", r.width - 26 - speakerWidth, r.height - 2);
g.drawString("" + bufferPercent + "%",
r.width - 26 - speakerWidth -subtitlesWidth, r.height - 2);
}
}
......@@ -205,7 +232,7 @@ public class Status extends Component implements MouseListener,
*/
private Rectangle getSeekBarRect() {
return new Rectangle(r.height*2 + 1, 2,
r.width - SEEK_TIME_GAP - TIME_WIDTH - speakerWidth - (r.height * 2),
r.width - SEEK_TIME_GAP - TIME_WIDTH - speakerWidth - subtitlesWidth - (r.height * 2),
r.height - 4);
}
......@@ -257,7 +284,7 @@ public class Status extends Component implements MouseListener,
r = getBounds();
end = r.width - speakerWidth - TIME_WIDTH;
end = r.width - speakerWidth - subtitlesWidth - TIME_WIDTH;
g.setColor(Color.white);
g.drawString("" + hour + ":" + (min < 10 ? "0" + min : "" + min) + ":"
......@@ -266,7 +293,13 @@ public class Status extends Component implements MouseListener,
private void paintSpeaker(Graphics g) {
if (haveAudio) {
g.drawImage(speakerImg, r.width - SPEAKER_WIDTH, r.height - SPEAKER_HEIGHT - 1, null);
g.drawImage(speakerImg, r.width - SPEAKER_WIDTH - subtitlesWidth, r.height - SPEAKER_HEIGHT - 1, null);
}
}
private void paintSubtitles(Graphics g) {
if (haveSubtitles) {
g.drawImage(subtitlesImg, r.width - SUBTITLES_WIDTH, r.height - SUBTITLES_HEIGHT - 1, null);
}
}
......@@ -320,6 +353,9 @@ public class Status extends Component implements MouseListener,
if (showSpeaker) {
paintSpeaker(g2);
}
if (showSubtitles) {
paintSubtitles(g2);
}
g.drawImage(img, r.x, r.y, null);
img.flush();
......@@ -392,6 +428,12 @@ public class Status extends Component implements MouseListener,
component.repaint();
}
public void setHaveSubtitles(boolean a) {
haveSubtitles = a;
subtitlesWidth = showSubtitles && haveSubtitles ? SUBTITLES_WIDTH : 0;
component.repaint();
}
public void setHavePercent(boolean p) {
havePercent = p;
component.repaint();
......@@ -413,6 +455,12 @@ public class Status extends Component implements MouseListener,
component.repaint();
}
public void setShowSubtitles(boolean s) {
showSubtitles = s;
subtitlesWidth = showSubtitles && haveSubtitles ? SUBTITLES_WIDTH : 0;
component.repaint();
}
public void setState(int aState) {
if (state != aState) {
state = aState;
......
......@@ -104,13 +104,17 @@ public class Selector extends Element
if (name.equals("selected")) {
int new_selected = Integer.valueOf(value.toString()).intValue();
Debug.info("Selector: request to select "+new_selected+" (from "+selected+"), within 0-"+(sinks.size()-1));
if (new_selected < 0 || new_selected >= sinks.size()) {
selected = -1;
selectedPad = null;
}
else {
selected = new_selected;
selectedPad = (Pad)sinks.elementAt(selected);
if (new_selected != selected) {
srcPad.pushEvent (Event.newFlushStart());
if (new_selected < 0 || new_selected >= sinks.size()) {
selected = -1;
selectedPad = null;
}
else {
selected = new_selected;
selectedPad = (Pad)sinks.elementAt(selected);
}
srcPad.pushEvent (Event.newFlushStop());
}
}
else {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment