Began implementing Quicktime for Java (QT4J) option in QD. As it is, Mac OS goes to Quicktime, while Windows goes to JMF. QT player stills needs some work.
This commit is contained in:
parent
7cb7f14759
commit
2ea513bab8
6 changed files with 1030 additions and 37 deletions
|
@ -45,7 +45,6 @@ import org.thdl.util.ThdlDebug;
|
|||
import org.thdl.util.ThdlActionListener;
|
||||
import org.thdl.util.ThdlAbstractAction;
|
||||
|
||||
|
||||
public class QD extends JDesktopPane {
|
||||
/** When opening a file, this is the only extension QuillDriver
|
||||
cares about. This is case-insensitive. */
|
||||
|
@ -58,7 +57,7 @@ public class QD extends JDesktopPane {
|
|||
protected SpeakerTable speakerTable;
|
||||
|
||||
//video related
|
||||
protected QDPlayer player = null;
|
||||
protected SmartMoviePanel player = null;
|
||||
|
||||
//frame related
|
||||
protected JInternalFrame videoFrame = null;
|
||||
|
@ -90,7 +89,7 @@ public class QD extends JDesktopPane {
|
|||
protected TibetanDocument findDoc = null;
|
||||
protected TibetanDocument replaceDoc = null;
|
||||
|
||||
protected URL keyboard_url = null;
|
||||
protected URL keyboard_url = null;
|
||||
|
||||
|
||||
public QD(ResourceBundle messages) {
|
||||
|
@ -109,7 +108,7 @@ public QD(ResourceBundle messages) {
|
|||
public void theRealActionPerformed(ActionEvent e) {
|
||||
new TimePoint(pane, clockIcon, tcp.getOutTime());
|
||||
tcp.setInTime(tcp.getOutTime().intValue());
|
||||
tcp.setOutTime(player.getLastTime());
|
||||
tcp.setOutTime(player.getEndTime());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -124,7 +123,7 @@ public QD(ResourceBundle messages) {
|
|||
if (p1 == p2)
|
||||
pane.setCaretPosition(pane.getCaretPosition()-1);
|
||||
tcp.setInTime(tcp.getOutTime().intValue());
|
||||
tcp.setOutTime(player.getLastTime());
|
||||
tcp.setOutTime(player.getEndTime());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -216,7 +215,7 @@ private void startTimer() {
|
|||
timer.schedule(new TimerTask() {
|
||||
public void run()
|
||||
{
|
||||
if (player.cmd_isSized())
|
||||
if (player.isInitialized())
|
||||
{
|
||||
timer.cancel();
|
||||
|
||||
|
@ -275,7 +274,7 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene
|
|||
if (e.getButton() == MouseEvent.BUTTON1)
|
||||
playSegment();
|
||||
else {
|
||||
SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getLastTime(), 10);
|
||||
SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getEndTime(), 10);
|
||||
JSpinner spinner = new JSpinner(snm1);
|
||||
spinner.setPreferredSize(new Dimension(100, 40));
|
||||
spinner.setValue(getTime());
|
||||
|
@ -306,17 +305,22 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene
|
|||
public void playSegment() {
|
||||
int i=pos.getOffset();
|
||||
System.out.println(String.valueOf(i));
|
||||
try {
|
||||
for (i++; i<doc.getLength(); i++) {
|
||||
AttributeSet attr = doc.getCharacterElement(i).getAttributes();
|
||||
Component comp;
|
||||
if (null != (comp = StyleConstants.getComponent(attr)))
|
||||
if (comp instanceof TimePoint) {
|
||||
TimePoint t2 = (TimePoint)comp;
|
||||
player.cmd_play(time, t2.time);
|
||||
player.cmd_playSegment(time, t2.time);
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.cmd_playFrom(time);
|
||||
player.cmd_playSegment(time, null);
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
}
|
||||
public void dragGestureRecognized(DragGestureEvent dge) {
|
||||
Transferable transferable = new TimePointTransferable(this);
|
||||
|
@ -429,7 +433,7 @@ class TimeCodeManager extends JPanel {
|
|||
setLayout(new BorderLayout());
|
||||
JPanel inPanel = new JPanel();
|
||||
JButton inButton = new JButton(messages.getString("In"));
|
||||
SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getLastTime(), 10);
|
||||
SpinnerNumberModel snm1 = new SpinnerNumberModel(0, 0, player.getEndTime(), 10);
|
||||
inSpinner = new JSpinner(snm1);
|
||||
inSpinner.setValue(new Integer(0));
|
||||
inSpinner.setPreferredSize(new Dimension(100, inButton.getPreferredSize().height));
|
||||
|
@ -438,7 +442,7 @@ class TimeCodeManager extends JPanel {
|
|||
|
||||
inButton.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
int k = player.when();
|
||||
int k = player.getCurrentTime();
|
||||
if (k != -1)
|
||||
setInTime(k);
|
||||
}
|
||||
|
@ -447,19 +451,24 @@ class TimeCodeManager extends JPanel {
|
|||
|
||||
JPanel outPanel = new JPanel();
|
||||
JButton outButton = new JButton(messages.getString("Out"));
|
||||
SpinnerNumberModel snm2 = new SpinnerNumberModel(0, 0, player.getLastTime(), 10);
|
||||
SpinnerNumberModel snm2 = new SpinnerNumberModel(0, 0, player.getEndTime(), 10);
|
||||
outSpinner = new JSpinner(snm2);
|
||||
outSpinner.setValue(new Integer(player.getLastTime()));
|
||||
outSpinner.setValue(new Integer(player.getEndTime()));
|
||||
outSpinner.setPreferredSize(new Dimension(100, inButton.getPreferredSize().height));
|
||||
outPanel.add(outButton);
|
||||
outPanel.add(outSpinner);
|
||||
|
||||
outButton.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
int k = player.when();
|
||||
int k = player.getCurrentTime();
|
||||
if (k != -1) {
|
||||
setOutTime(k);
|
||||
try {
|
||||
player.cmd_stop();
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -470,8 +479,14 @@ class TimeCodeManager extends JPanel {
|
|||
public void theRealActionPerformed(ActionEvent e) {
|
||||
Integer in = getInTime();
|
||||
Integer out = getOutTime();
|
||||
if (out.intValue() > in.intValue())
|
||||
player.cmd_play(in, out);
|
||||
if (out.intValue() > in.intValue()) {
|
||||
try {
|
||||
player.cmd_playSegment(in, out);
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
JPanel ps = new JPanel();
|
||||
|
@ -483,14 +498,26 @@ class TimeCodeManager extends JPanel {
|
|||
|
||||
playButton.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
if (player != null)
|
||||
player.cmd_play();
|
||||
if (player != null) {
|
||||
try {
|
||||
player.cmd_playOn();
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
pauseButton.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
if (player != null)
|
||||
if (player != null) {
|
||||
try {
|
||||
player.cmd_stop();
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
@ -578,8 +605,13 @@ public void setMedia(File f) {
|
|||
media = f;
|
||||
mediaField.setText(media.getPath());
|
||||
if (player != null) {
|
||||
try {
|
||||
player.cmd_stop();
|
||||
player.destroy();
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
videoFrame.getContentPane().remove(player);
|
||||
videoFrame.getContentPane().invalidate();
|
||||
videoFrame.getContentPane().validate();
|
||||
|
@ -597,13 +629,33 @@ public void setMedia(File f) {
|
|||
URL url = f.toURL();
|
||||
|
||||
if (player != null) {
|
||||
try {
|
||||
player.cmd_stop();
|
||||
player.destroy();
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//if user properties opt for qt4j instead of jmf, then load qt4j instead
|
||||
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
try {
|
||||
if (os.indexOf("windows") != -1) {
|
||||
player = new SmartJMFPlayer(QD.this, url);
|
||||
} else if (os.indexOf("mac") != -1) {
|
||||
player = new SmartQT4JPlayer();
|
||||
player.loadMovie(url);
|
||||
}
|
||||
player = new QDPlayer(QD.this, url);
|
||||
media = f;
|
||||
mediaField.setText(media.getPath());
|
||||
startTimer();
|
||||
} catch (SmartMoviePanelException smpe) {
|
||||
smpe.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
}
|
||||
} catch (MalformedURLException murle) {
|
||||
murle.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
|
@ -893,6 +945,7 @@ if (keyboard_url != null) {
|
|||
|
||||
dp.registerKeyboard();
|
||||
// project.tName.setupKeyboard();
|
||||
|
||||
// project.tTask.setupKeyboard();
|
||||
sharedDP.setupKeyboard();
|
||||
sharedDP2.setupKeyboard();
|
||||
|
|
67
source/org/thdl/quilldriver/QDtoHTML.xsl
Normal file
67
source/org/thdl/quilldriver/QDtoHTML.xsl
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
|
||||
xmlns:jskad="xalan://org.thdl.tib.text">
|
||||
|
||||
<xsl:output method="html"/>
|
||||
<xsl:template match="qd">
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
<xsl:value-of select="jskad:TibetanHTML.getStyles(28)" disable-output-escaping="yes"/>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<xsl:apply-templates select="metadata/title" />
|
||||
<xsl:apply-templates select="text" />
|
||||
<xsl:apply-templates select="metadata/workhistory" />
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="title">
|
||||
<xsl:value-of select="." />
|
||||
<p />
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text">
|
||||
<xsl:apply-templates select="node()" />
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="who">
|
||||
<p />
|
||||
<xsl:variable name="idvar" select="@id" />
|
||||
<xsl:variable name="name" select="../../metadata/speakers/speaker[@iconid=$idvar]" />
|
||||
<u><xsl:value-of select="jskad:TibetanHTML.getHTML($name)" disable-output-escaping="yes"/></u>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text()">
|
||||
<xsl:value-of select="jskad:TibetanHTML.getIndentedHTML(.)" disable-output-escaping="yes"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="workhistory">
|
||||
<p />
|
||||
<b>Work History</b>
|
||||
<p/>
|
||||
<table width="100%" border="1">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Task</th>
|
||||
<th>Start Time</th>
|
||||
<th>Duration</th>
|
||||
</tr>
|
||||
<xsl:apply-templates select="work"/>
|
||||
</table>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="work">
|
||||
<tr>
|
||||
<td><xsl:value-of select="name" disable-output-escaping="yes"/></td>
|
||||
<td><xsl:value-of select="task" disable-output-escaping="yes"/></td>
|
||||
<td><xsl:value-of select="start" /></td>
|
||||
<td><xsl:value-of select="duration" /> minutes</td>
|
||||
</tr>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
379
source/org/thdl/quilldriver/SmartJMFPlayer.java
Normal file
379
source/org/thdl/quilldriver/SmartJMFPlayer.java
Normal file
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
The contents of this file are subject to the THDL Open Community License
|
||||
Version 1.0 (the "License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License on the THDL web site
|
||||
(http://www.thdl.org/).
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS" basis,
|
||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
License for the specific terms governing rights and limitations under the
|
||||
License.
|
||||
|
||||
The Initial Developer of this software is the Tibetan and Himalayan Digital
|
||||
Library (THDL). Portions created by the THDL are Copyright 2001 THDL.
|
||||
All Rights Reserved.
|
||||
|
||||
Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
package org.thdl.quilldriver;
|
||||
|
||||
import java.util.*;
|
||||
import java.net.*;
|
||||
import javax.media.*;
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import org.thdl.util.ThdlDebug;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
public class SmartJMFPlayer extends SmartMoviePanel implements ControllerListener
|
||||
{
|
||||
private EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
public URL mediaURL;
|
||||
|
||||
private Player player = null;
|
||||
private Component visualComponent = null;
|
||||
private Component controlComponent = null;
|
||||
private Panel panel = null;
|
||||
private JPanel vPanel = null;
|
||||
|
||||
private Container parent = null;
|
||||
|
||||
private java.util.Timer timer = null;
|
||||
private Time stopTime = null;
|
||||
private Time pauseTime = null;
|
||||
private boolean stillLoadingVideo = false;
|
||||
private boolean isMediaAudio = false;
|
||||
private boolean isSized = false;
|
||||
|
||||
private Float to = null;
|
||||
/*-----------------------------------------------------------------------*/
|
||||
public SmartJMFPlayer(Container p, URL sound) throws SmartMoviePanelException {
|
||||
super( new GridLayout() );
|
||||
parent = p;
|
||||
loadMovie(sound);
|
||||
}
|
||||
public void loadMovie(URL sound) throws SmartMoviePanelException {
|
||||
if (mediaURL != null) {
|
||||
cmd_stop();
|
||||
destroy();
|
||||
}
|
||||
mediaURL = sound;
|
||||
start();
|
||||
}
|
||||
public void destroy() throws SmartMoviePanelException {
|
||||
if (false)
|
||||
throw new SmartMoviePanelException();
|
||||
player.close();
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
private void start() {
|
||||
try {
|
||||
player = Manager.createPlayer(mediaURL);
|
||||
player.addControllerListener(this);
|
||||
} catch (javax.media.NoPlayerException e) {
|
||||
System.err.println("noplayer exception");
|
||||
e.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
return;
|
||||
} catch (java.io.IOException ex) {
|
||||
System.err.println("IO exception");
|
||||
ex.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
return;
|
||||
}
|
||||
if (player != null)
|
||||
player.realize();
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
public void displayBorders(boolean borders) throws SmartMoviePanelException
|
||||
{
|
||||
if (false)
|
||||
throw new SmartMoviePanelException();
|
||||
}
|
||||
public void displayController(boolean controller) throws SmartMoviePanelException
|
||||
{
|
||||
if (false)
|
||||
throw new SmartMoviePanelException();
|
||||
|
||||
}
|
||||
public boolean isInitialized() {
|
||||
return isSized;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
public synchronized void controllerUpdate(ControllerEvent event) {
|
||||
if (player == null)
|
||||
return;
|
||||
if (event instanceof RealizeCompleteEvent) {
|
||||
System.out.println("received RealizeCompleteEvent event");
|
||||
if (visualComponent == null) {
|
||||
if (panel == null) {
|
||||
setLayout(new GridLayout(1,1));
|
||||
vPanel = new JPanel();
|
||||
vPanel.setLayout( new BorderLayout() );
|
||||
if ((visualComponent = player.getVisualComponent())!= null)
|
||||
vPanel.add("Center", visualComponent);
|
||||
else {
|
||||
isMediaAudio = true;
|
||||
stillLoadingVideo = false;
|
||||
}
|
||||
if (!stillLoadingVideo)
|
||||
{
|
||||
if ((controlComponent = player.getControlPanelComponent()) != null) {
|
||||
if (visualComponent == null) //no video
|
||||
vPanel.setPreferredSize(new Dimension(400,25));
|
||||
vPanel.add("South", controlComponent);
|
||||
}
|
||||
}
|
||||
add(vPanel);
|
||||
}
|
||||
}
|
||||
parent.invalidate();
|
||||
parent.validate();
|
||||
parent.repaint();
|
||||
isSized = true;
|
||||
if (stillLoadingVideo)
|
||||
player.start();
|
||||
} else if (event instanceof StartEvent) {
|
||||
StartEvent se = (StartEvent)event;
|
||||
Time t = se.getMediaTime();
|
||||
long longt = t.getNanoseconds();
|
||||
Float from = new Float(longt);
|
||||
float f = (from.floatValue() / 1000000000);
|
||||
from = new Float(f);
|
||||
t = player.getStopTime();
|
||||
longt = t.getNanoseconds();
|
||||
to = new Float(longt);
|
||||
f = (to.floatValue() / 1000000000);
|
||||
to = new Float(f);
|
||||
if (timer != null)
|
||||
{
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
timer = new java.util.Timer(true);
|
||||
timer.schedule(new TimerTask() {
|
||||
public void run() {
|
||||
//this is specifically for the MPG stop time bug
|
||||
if (stopTime != null)
|
||||
if (player.getMediaTime().getNanoseconds() > stopTime.getNanoseconds())
|
||||
player.stop();
|
||||
}}, 0, 15);
|
||||
} else if (event instanceof StopEvent) {
|
||||
pauseTime = player.getMediaTime();
|
||||
|
||||
|
||||
/*messy problems require messy solutions:
|
||||
if the slider is present, dragging it while playing creates
|
||||
a RestartingEvent, and if I set the media time here it messes up
|
||||
and barely plays at all (maybe because it cancels the previously
|
||||
set media time? - I don't know).
|
||||
|
||||
but it seems that if you press the play/pause button on the
|
||||
control widget, then you need to set the media time upon stop
|
||||
(probably because of problem noted below, namely that you get
|
||||
weird results if you do player.start() without setting the media
|
||||
time.*/
|
||||
|
||||
if (!(event instanceof RestartingEvent))
|
||||
player.setMediaTime(pauseTime);
|
||||
|
||||
// player.setStopTime(Clock.RESET);
|
||||
stopTime = null;
|
||||
|
||||
System.out.println("received StopEvent");
|
||||
|
||||
if (timer != null)
|
||||
{
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
if (stillLoadingVideo)
|
||||
{
|
||||
System.out.println("received EndOfMediaEvent");
|
||||
stillLoadingVideo = false;
|
||||
player.stop();
|
||||
if ((controlComponent = player.getControlPanelComponent()) != null) {
|
||||
if (visualComponent == null) //no video
|
||||
vPanel.setPreferredSize(new Dimension(400,25));
|
||||
vPanel.add("South", controlComponent);
|
||||
}
|
||||
parent.invalidate();
|
||||
parent.validate();
|
||||
parent.repaint();
|
||||
}
|
||||
} else if ( event instanceof CachingControlEvent) {
|
||||
CachingControlEvent e = (CachingControlEvent) event;
|
||||
System.out.println("got CachingControlEvent: " + e);
|
||||
if (!isMediaAudio)
|
||||
stillLoadingVideo = true;
|
||||
} else if (event instanceof ControllerErrorEvent) {
|
||||
player = null;
|
||||
System.err.println("*** ControllerErrorEvent *** " + ((ControllerErrorEvent)event).getMessage());
|
||||
} else if (event instanceof PrefetchCompleteEvent) {
|
||||
if (panel != null) {
|
||||
panel.invalidate();
|
||||
}
|
||||
parent.invalidate();
|
||||
parent.validate();
|
||||
parent.repaint();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
public void cmd_stop() throws SmartMoviePanelException {
|
||||
if (player == null)
|
||||
throw new SmartMoviePanelException("no player");
|
||||
try {
|
||||
player.stop();
|
||||
} catch (NotRealizedError err) {
|
||||
throw new SmartMoviePanelException("JMF player not realized");
|
||||
}
|
||||
}
|
||||
public void cmd_playOn() throws SmartMoviePanelException {
|
||||
if (stillLoadingVideo || player == null) {
|
||||
throw new SmartMoviePanelException("no player or video still loading");
|
||||
}
|
||||
if (player.getState() == Controller.Started)
|
||||
return;
|
||||
|
||||
if (pauseTime == null)
|
||||
player.setMediaTime(new Time(0.0));
|
||||
else
|
||||
player.setMediaTime(pauseTime);
|
||||
if (player.getTargetState() < Player.Started) {
|
||||
player.setStopTime(Clock.RESET);
|
||||
player.prefetch();
|
||||
}
|
||||
player.start();
|
||||
}
|
||||
public void cmd_playSegment(Integer from, Integer to) throws SmartMoviePanelException {
|
||||
if (from == null || player == null || stillLoadingVideo)
|
||||
throw new SmartMoviePanelException("no player or video still loading");
|
||||
|
||||
final Time startTime = new Time(from.longValue() * 1000000);
|
||||
try {
|
||||
if (player.getState() == Controller.Started)
|
||||
player.stop();
|
||||
while (player.getState() == Controller.Unrealized)
|
||||
;
|
||||
if (to == null) {
|
||||
stopTime = null;
|
||||
player.setStopTime(Clock.RESET);
|
||||
} else {
|
||||
stopTime = new Time(to.longValue() * 1000000);
|
||||
player.setStopTime(stopTime);
|
||||
}
|
||||
player.setMediaTime(startTime);
|
||||
player.prefetch();
|
||||
player.start();
|
||||
} catch(NotRealizedError err) {
|
||||
throw new SmartMoviePanelException("JMF player not realized");
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
public int getCurrentTime() {
|
||||
if (player == null)
|
||||
return -1;
|
||||
if (player.getState() < Controller.Realized)
|
||||
return -1;
|
||||
long currTime = player.getMediaNanoseconds();
|
||||
return new Long(currTime / 1000000).intValue();
|
||||
}
|
||||
public int getEndTime() {
|
||||
Time t = player.getDuration();
|
||||
long l = t.getNanoseconds();
|
||||
return new Long(l / 1000000).intValue();
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
After pause the MPEG video and playing it again it gets faster
|
||||
Author: vladshtr
|
||||
In Reply To: After pause the MPEG video and playing it again it gets faster
|
||||
Mar 1, 2001 6:25 PM
|
||||
|
||||
Reply 1 of 1
|
||||
|
||||
|
||||
The problem is in the setting the Media time.
|
||||
|
||||
The safety way is to always set new media time with the
|
||||
following method: setMediaTime(Time time); .... if you want to
|
||||
use it after
|
||||
-player.stop(); used as real stop you can use setMediaTime(new
|
||||
Time(0.0));
|
||||
-player.stop(); used as real pause you have to use the
|
||||
combination:
|
||||
player.stop();
|
||||
Time currentTime = player.getMediaTime();
|
||||
//........
|
||||
player.setMediaTime(currentTime);
|
||||
player.start();
|
||||
|
||||
|
||||
Re: (urgent) when you pause and resume, video plays at rate > 1
|
||||
Author: seertenedos
|
||||
In Reply To: (urgent) when you pause and resume, video plays at rate > 1
|
||||
Aug 11, 2002 11:36 PM
|
||||
|
||||
Reply 1 of 1
|
||||
|
||||
|
||||
I found a solution for this problem for those that are interested.
|
||||
|
||||
what you have to do is store the time just before you pause and then set the
|
||||
time just before you play. here is a copy of my pause and play methods
|
||||
|
||||
// Start the player
|
||||
private void play() {
|
||||
if (player != null)
|
||||
{
|
||||
if (pauseTime != null)
|
||||
{
|
||||
player.setMediaTime(pauseTime);
|
||||
}
|
||||
if (player.getTargetState() < Player.Started)
|
||||
player.prefetch();
|
||||
player.start();
|
||||
}
|
||||
}
|
||||
|
||||
// Pause the player
|
||||
private void pause() {
|
||||
if (player != null)
|
||||
pauseTime = player.getMediaTime();
|
||||
player.stop();
|
||||
}
|
||||
|
||||
|
||||
that should solve your pause play problems!
|
||||
|
||||
> The problem is below. It seems quite a few people are
|
||||
> having this problem but i have not seen a solution
|
||||
> around. I really need a solution to this problem as
|
||||
> the whole point of my application is that it plays
|
||||
> divx and mpeg videos. At the moment i have divx
|
||||
> movies playing through the mpeg demuxer as the avi one
|
||||
> stuffed up the audio. I think that is the reason it
|
||||
> affects both divx and mpeg. My application is due in
|
||||
> one week and my client is not going to be very happy
|
||||
> if this problem happens every time they pause then
|
||||
> play the video.
|
||||
> The player is for divx movies. If anyone knows how to
|
||||
> solve this problem or how to make it so you can pause
|
||||
> and resume divx movies please respond.
|
||||
>
|
||||
> Pause and Resume playback.
|
||||
> The video plays at a high rate and there is no audio.
|
||||
> Problem doesn't appear while seeking.
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
|
||||
*/
|
30
source/org/thdl/quilldriver/SmartMoviePanel.java
Normal file
30
source/org/thdl/quilldriver/SmartMoviePanel.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package org.thdl.quilldriver;
|
||||
|
||||
import java.awt.*;
|
||||
import java.net.*;
|
||||
|
||||
public abstract class SmartMoviePanel extends Panel
|
||||
{
|
||||
//helper methods - initialize
|
||||
public abstract void displayBorders(boolean borders) throws SmartMoviePanelException;
|
||||
public abstract void displayController(boolean controller) throws SmartMoviePanelException;
|
||||
public abstract void loadMovie(URL mediaUrl) throws SmartMoviePanelException;
|
||||
|
||||
//helper methods - control media
|
||||
public abstract void cmd_playOn() throws SmartMoviePanelException;
|
||||
public abstract void cmd_playSegment(Integer startTime, Integer stopTime) throws SmartMoviePanelException;
|
||||
public abstract void cmd_stop() throws SmartMoviePanelException;
|
||||
|
||||
//helper methods - media status
|
||||
public abstract boolean isInitialized();
|
||||
public abstract int getCurrentTime();
|
||||
public abstract int getEndTime();
|
||||
|
||||
//helper methods - cleanup
|
||||
public abstract void destroy() throws SmartMoviePanelException;
|
||||
//constructor
|
||||
public SmartMoviePanel(GridLayout layout)
|
||||
{
|
||||
super(layout);
|
||||
}
|
||||
}
|
13
source/org/thdl/quilldriver/SmartMoviePanelException.java
Normal file
13
source/org/thdl/quilldriver/SmartMoviePanelException.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
package org.thdl.quilldriver;
|
||||
|
||||
public class SmartMoviePanelException extends Exception
|
||||
{
|
||||
public SmartMoviePanelException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
public SmartMoviePanelException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
451
source/org/thdl/quilldriver/SmartQT4JPlayer.java
Normal file
451
source/org/thdl/quilldriver/SmartQT4JPlayer.java
Normal file
|
@ -0,0 +1,451 @@
|
|||
package org.thdl.quilldriver;
|
||||
|
||||
import java.awt.*;
|
||||
import java.net.*;
|
||||
import quicktime.*;
|
||||
import quicktime.app.*;
|
||||
import quicktime.app.display.*;
|
||||
import quicktime.app.players.*;
|
||||
import quicktime.app.image.*; //required for the QT4JAVA test
|
||||
import quicktime.std.*;
|
||||
import quicktime.std.movies.*;
|
||||
import quicktime.std.movies.media.DataRef;
|
||||
import quicktime.io.*;
|
||||
import quicktime.app.time.*;
|
||||
import quicktime.std.clocks.*;
|
||||
|
||||
public class SmartQT4JPlayer extends SmartMoviePanel
|
||||
{
|
||||
//attributes
|
||||
private QTCanvas canvas; //this hands over screen real estate to
|
||||
//native graphics that quicktime can control
|
||||
|
||||
private QTPlayer player; //this is the the client for the canvas
|
||||
//In my app it will get set to a
|
||||
// quicktime.app.player object
|
||||
|
||||
private Movie movie; //this is the content used in
|
||||
//QTDrawable player's quicktime.app.player constructor
|
||||
|
||||
private MovieController controller;
|
||||
|
||||
private TimeBaseRateCallBack theMoviesRateCallback;
|
||||
private TimeBaseExtremesCallBack theMoviesExtremeCallback;
|
||||
private TimeBaseTimeJumpCallBack theMoviesTimeJumpCallback;
|
||||
private TimeBaseTimeCallBack theMoviesTimeCallback;
|
||||
private TimeBaseTimeCallBackStopper theStopper;
|
||||
|
||||
//accessors
|
||||
public void setPlayer(QTPlayer player)
|
||||
{
|
||||
this.player = player;
|
||||
}
|
||||
public QTPlayer getPlayer()
|
||||
{
|
||||
return player;
|
||||
}
|
||||
|
||||
public void setMovie(Movie movie)
|
||||
{
|
||||
this.movie = movie;
|
||||
}
|
||||
public void setMovie(URL movieURL)
|
||||
{
|
||||
try
|
||||
{
|
||||
DataRef movieDataRef = new DataRef( "file://" + movieURL.getFile() );
|
||||
Movie m = new Movie();
|
||||
m = m.fromDataRef( movieDataRef, StdQTConstants.newMovieActive );
|
||||
setMovie(m);
|
||||
getMovie().setTimeScale(1000);
|
||||
}
|
||||
catch(QTException qte)
|
||||
{
|
||||
qte.printStackTrace();
|
||||
System.out.println( movieURL.toString() );
|
||||
}
|
||||
}
|
||||
public Movie getMovie()
|
||||
{
|
||||
return movie;
|
||||
}
|
||||
|
||||
public void setController(MovieController controller)
|
||||
{
|
||||
this.controller = controller;
|
||||
}
|
||||
public MovieController getController()
|
||||
{
|
||||
return controller;
|
||||
}
|
||||
|
||||
public void setCanvas(QTCanvas canvas)
|
||||
{
|
||||
this.canvas = canvas;
|
||||
}
|
||||
public QTCanvas getCanvas()
|
||||
{
|
||||
return canvas;
|
||||
}
|
||||
|
||||
|
||||
//contract methods - initialize
|
||||
public void displayBorders(boolean borders) throws SmartMoviePanelException
|
||||
{
|
||||
}
|
||||
public void displayController(boolean controller) throws SmartMoviePanelException
|
||||
{
|
||||
}
|
||||
public void loadMovie(URL mediaURL) throws SmartMoviePanelException
|
||||
{
|
||||
setMovie(mediaURL);
|
||||
try
|
||||
{
|
||||
getCanvas().removeClient();
|
||||
setController( new MovieController( getMovie() ));
|
||||
getController().setKeysEnabled(true);
|
||||
setPlayer(new QTPlayer( getController() ));
|
||||
getCanvas().setClient( getPlayer(), true );
|
||||
this.add( getCanvas() );
|
||||
TimeBase theMoviesTimeBase = getMovie().getTimeBase();
|
||||
|
||||
// this callback is triggered when the rate of the movie changes
|
||||
theMoviesRateCallback = new TimeBaseRateCallBack(theMoviesTimeBase, 1.0F, StdQTConstants.triggerRateChange);
|
||||
// theMoviesRateCallback.callMeWhen();
|
||||
|
||||
// this callback is triggered when the movie ends
|
||||
theMoviesExtremeCallback = new TimeBaseExtremesCallBack(theMoviesTimeBase, StdQTConstants.triggerAtStop);
|
||||
// theMoviesExtremeCallback.callMeWhen();
|
||||
|
||||
// this callback is triggered when the movie starts
|
||||
theMoviesExtremeCallback = new TimeBaseExtremesCallBack(theMoviesTimeBase, StdQTConstants.triggerAtStart);
|
||||
// theMoviesExtremeCallback.callMeWhen();
|
||||
|
||||
// this callback is triggered when there is a jump in the timebase
|
||||
theMoviesTimeJumpCallback = new TimeBaseTimeJumpCallBack(theMoviesTimeBase);
|
||||
// theMoviesTimeJumpCallback.callMeWhen();
|
||||
|
||||
// this schedules the time callback once every 2 seconds
|
||||
// this callback is triggered at a specific time interval
|
||||
theMoviesTimeCallback = new TimeBaseTimeCallBack(theMoviesTimeBase, 1, 2, StdQTConstants.triggerTimeEither);
|
||||
// theMoviesTimeCallback.callMeWhen();
|
||||
|
||||
//Using the Timer class you can get rescheduled properly and get callbacks at the set intervals. It uses the same callback
|
||||
//mechanism of internally of the TimeCallback.
|
||||
//Its recomended to use this Timer class to do callbacks , which would take care of the time base time changes and
|
||||
//recscheduling of the tickle method .
|
||||
Timer timer = new Timer(1, 2, new Tickler(), getMovie() );
|
||||
// timer.setActive(true);
|
||||
|
||||
}
|
||||
catch(QTException qte)
|
||||
{
|
||||
qte.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//contract methods - control media
|
||||
public void cmd_playOn() throws SmartMoviePanelException
|
||||
{
|
||||
try
|
||||
{
|
||||
getPlayer().setRate(1.0F);
|
||||
}
|
||||
catch(QTException qte)
|
||||
{
|
||||
qte.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void cmd_playSegment(Integer startTime, Integer stopTime) throws SmartMoviePanelException
|
||||
{
|
||||
try
|
||||
{
|
||||
getPlayer().setTime( startTime.intValue() );
|
||||
|
||||
int value=stopTime.intValue();
|
||||
TimeBase theMoviesTimeBase = getPlayer().getTimeBase();
|
||||
theStopper = new TimeBaseTimeCallBackStopper(theMoviesTimeBase, 1000, value, StdQTConstants.triggerTimeEither);
|
||||
theStopper.callMeWhen();
|
||||
|
||||
cmd_playOn();
|
||||
|
||||
System.out.println("Set start time to " +startTime.intValue() );
|
||||
System.out.println("Set stop time " +stopTime.intValue() );
|
||||
System.out.println("Current time " +getPlayer().getTime() );
|
||||
System.out.println("Time Stopper's stop trigger " +theStopper.getCallTime() );
|
||||
System.out.println("Player Scale: " +getPlayer().getScale() );
|
||||
System.out.println("Movie Scale: " +getMovie().getTimeScale() );
|
||||
|
||||
}
|
||||
catch (SmartMoviePanelException smpe) {}
|
||||
catch (StdQTException sqte) {}
|
||||
catch (QTException qte) {}
|
||||
}
|
||||
public void cmd_stop() throws SmartMoviePanelException
|
||||
{
|
||||
try
|
||||
{
|
||||
getPlayer().setRate(0.0F);
|
||||
}
|
||||
catch(QTException qte)
|
||||
{
|
||||
qte.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//contract methods - media status
|
||||
public boolean isInitialized()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public int getCurrentTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public int getEndTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//helper methods - QT4J
|
||||
public void startupQTSession()
|
||||
{
|
||||
//Initialize a QT session and add a test image
|
||||
|
||||
//These three try/catch blocks come from PlayMovie.java copyright
|
||||
// Apple Co. I'm using it to test that QT and QT4Java exist
|
||||
try
|
||||
{
|
||||
if (QTSession.isInitialized() == false)
|
||||
QTSession.open();
|
||||
}
|
||||
catch (NoClassDefFoundError er)
|
||||
{
|
||||
add (new Label ("Can't Find QTJava classes"), "North");
|
||||
add (new Label ("Check install and try again"), "South");
|
||||
}
|
||||
catch (SecurityException se)
|
||||
{
|
||||
// this is thrown by MRJ trying to find QTSession class
|
||||
add (new Label ("Can't Find QTJava classes"), "North");
|
||||
add (new Label ("Check install and try again"), "South");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// do a dynamic test for QTException
|
||||
//so the QTException class is not loaded unless
|
||||
// an unknown exception is thrown by the runtime
|
||||
if (e instanceof ClassNotFoundException || e instanceof java.io.FileNotFoundException)
|
||||
{
|
||||
add (new Label ("Can't Find QTJava classes"), "North");
|
||||
add (new Label ("Check install and try again"), "South");
|
||||
}
|
||||
else if (e instanceof QTException)
|
||||
{
|
||||
add (new Label ("Problem with QuickTime install"), "North");
|
||||
if (((QTException)e).errorCode() == -2093)
|
||||
add (new Label ("QuickTime must be installed"), "South");
|
||||
else
|
||||
add (new Label (e.getMessage()), "South");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
setCanvas( new QTCanvas(QTCanvas.kInitialSize, 0.5F, 0.5F) );
|
||||
this.add( getCanvas() );
|
||||
getCanvas().setClient(ImageDrawer.getQTLogo(), true);
|
||||
}
|
||||
catch(QTException qte)
|
||||
{
|
||||
qte.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
QTSession.close();
|
||||
System.out.println("Clean up performed.");
|
||||
}
|
||||
|
||||
//constructor
|
||||
public SmartQT4JPlayer(Container cont, URL mediaURL)
|
||||
{
|
||||
super( new GridLayout() );
|
||||
startupQTSession();
|
||||
}
|
||||
public SmartQT4JPlayer()
|
||||
{
|
||||
super( new GridLayout() );
|
||||
startupQTSession();
|
||||
}
|
||||
|
||||
// inner classes
|
||||
/**
|
||||
* This class extends the RateCallBack class and provides an execute routine
|
||||
* that is invoked by the callback when the rate of the movie changes
|
||||
*
|
||||
*@author travis
|
||||
*@created September 3, 2002
|
||||
*/
|
||||
|
||||
public class TimeBaseRateCallBack extends RateCallBack
|
||||
{
|
||||
public TimeBaseRateCallBack(TimeBase tb, float rate, int flag) throws QTException
|
||||
{
|
||||
super(tb, rate, flag);
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("--- RateCallBack@ratechange---");
|
||||
|
||||
cancel();
|
||||
//reschedule
|
||||
callMeWhen();
|
||||
|
||||
} catch (StdQTException e)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class implements a method that is called when the movie stops
|
||||
*
|
||||
*@author travis
|
||||
*@created September 3, 2002
|
||||
*/
|
||||
|
||||
class TimeBaseExtremesCallBack extends quicktime.std.clocks.ExtremesCallBack
|
||||
{
|
||||
|
||||
public TimeBaseExtremesCallBack(TimeBase tb, int flag) throws QTException
|
||||
{
|
||||
super(tb, flag);
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("--- ExtremesCallBack@stop---");
|
||||
|
||||
//cancel
|
||||
cancel();
|
||||
//reschedule
|
||||
callMeWhen();
|
||||
}
|
||||
catch (StdQTException e)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class extends the TimeJumpCallBack class to provide a method that is
|
||||
* called when the timebase of the movie changes (IE, if the user clicks in
|
||||
* the movie controller)
|
||||
*
|
||||
*@author travis
|
||||
*@created September 3, 2002
|
||||
*/
|
||||
|
||||
class TimeBaseTimeJumpCallBack extends quicktime.std.clocks.TimeJumpCallBack
|
||||
{
|
||||
public TimeBaseTimeJumpCallBack(TimeBase tb) throws QTException
|
||||
{
|
||||
super(tb);
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("--- TimeJumpCallBack---");
|
||||
|
||||
cancel();
|
||||
//reschedule
|
||||
callMeWhen();
|
||||
}
|
||||
catch (StdQTException e)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
class TimeBaseTimeCallBack extends quicktime.std.clocks.TimeCallBack
|
||||
{
|
||||
private int callTime;
|
||||
private TimeBase theTimeBase;
|
||||
|
||||
public void setCallTime(int time)
|
||||
{
|
||||
callTime=time;
|
||||
value=callTime;
|
||||
}
|
||||
public int getCallTime()
|
||||
{
|
||||
return callTime;
|
||||
}
|
||||
public void execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("--- TimeCallBack@triggerTimeEither--- called at:" + timeWhenCalledMsecs + "msecs");
|
||||
|
||||
cancel();
|
||||
//reschedule
|
||||
callMeWhen();
|
||||
}
|
||||
catch (StdQTException e)
|
||||
{}
|
||||
}
|
||||
public TimeBaseTimeCallBack(TimeBase tb, int scale, int value, int flags) throws QTException
|
||||
{
|
||||
super(tb, scale, value, flags);
|
||||
// setCallTime(value/1000);
|
||||
setCallTime(value);
|
||||
theTimeBase = tb;
|
||||
}
|
||||
}
|
||||
|
||||
class TimeBaseTimeCallBackStopper extends TimeBaseTimeCallBack
|
||||
{
|
||||
public void execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("---TimeCallBackStopper--- called at:" + timeWhenCalledMsecs + "msecs");
|
||||
System.out.println("---TimeCallBackStopper--- callTime is: " + getCallTime() + " msecs");
|
||||
cmd_stop();
|
||||
System.out.println("---TimeCallBackStopper--- Player time is: " + getPlayer().getTime() + " msecs");
|
||||
System.out.println("---TimeCallBackStopper--- Movie time is: " + getMovie().getTime() + " msecs");
|
||||
|
||||
cancelAndCleanup();
|
||||
//reschedule
|
||||
//callMeWhen();
|
||||
}
|
||||
catch (StdQTException e) {}
|
||||
catch (SmartMoviePanelException smpe) {}
|
||||
}
|
||||
public TimeBaseTimeCallBackStopper(TimeBase tb, int scale, int value, int flags) throws QTException
|
||||
{
|
||||
super(tb, scale, value, flags);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Tickler implements Ticklish
|
||||
{
|
||||
public void timeChanged(int newTime) throws QTException
|
||||
{
|
||||
System.out.println("* * * * Timer Class * * * timeChanged at:" + newTime);
|
||||
}
|
||||
|
||||
public boolean tickle(float er, int time) throws QTException
|
||||
{
|
||||
System.out.println("* * * * Timer Class * * * tickle at:" + time);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue