/*
* Apollo - Motion capture and animation system
* Copyright (c) 2005 Apollo
*
* This program is free software; you can redistribute it 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.
*
* http://www.gnu.org/copyleft/gpl.html
*
* @author Giovane.Kuhn - brain@netuno.com.br
*
*/
package org.apollo.player;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import javax.media.Duration;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoProcessorException;
import javax.media.NotConfiguredError;
import javax.media.Processor;
import javax.media.Time;
import javax.media.UnsupportedPlugInException;
import javax.media.control.FramePositioningControl;
import javax.media.control.TrackControl;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import jmapps.util.StateHelper;
import org.apollo.ApolloUtil;
import org.apollo.MediaUtil;
import org.apollo.datamodel.Video;
import org.apollo.i18n.ApolloResource;
import org.apollo.renderer.OpenGLRenderer;
import org.apollo.view.PropertyPanel;
/**
* Panel to play a video, render with OpenGL
* @author Giovane.Kuhn on 26/05/2005
*/
public final class OpenGLPlayerPanel extends PropertyPanel implements IPlayer {
private static final long serialVersionUID = 1L;
/** Video renderer */
protected final OpenGLRenderer renderer;
/** Thread to execute video */
private final Animator animator;
/** Video player */
private Processor player;
/** Video frame controling */
private FramePositioningControl fpc;
/** Video to play */
private Video video;
/** Label to show frame number */
private JLabel frameLabel;
/** Total frame on video */
private int framesTotal;
public OpenGLPlayerPanel() {
this.renderer = new OpenGLRenderer(this);
this.animator = new Animator();
this.animator.start();
this.add(new JScrollPane(renderer.getComponent()), REMAINDER_POSITION, 1, BOTH_RESIZABLE);
JButton item;
this.add(item = new JButton(ApolloResource.getText("panel.player.button.backward")), 1, 1, WIDTH_RESIZABLE);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
step(-1);
}
});
this.add(item = new JButton(ApolloResource.getText("panel.player.button.start")), 1, 1, WIDTH_RESIZABLE);
this.add(frameLabel = new JLabel(""), 1, 1, NONE_RESIZABLE);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
start();
}
});
this.add(item = new JButton(ApolloResource.getText("panel.player.button.stop")), 1, 1, WIDTH_RESIZABLE);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stop();
}
});
this.add(item = new JButton(ApolloResource.getText("panel.player.button.forward")), REMAINDER_POSITION, 1, WIDTH_RESIZABLE);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
step(1);
}
});
}
/**
* Return player video renderer
* @return An instance of {@link org.apollo.renderer.OpenGLRenderer OpenGLRenderer}
*/
public OpenGLRenderer getRenderer() {
return renderer;
}
/**
* Refresh frame numbers on diplay
*/
public void refreshDisplay() {
frameLabel.setText((getActualFrame() + 1) + " / " + framesTotal);
frameLabel.repaint();
}
public int getTotalFrames() {
return framesTotal;
}
public int getActualFrame() {
return fpc.mapTimeToFrame(player.getMediaTime());
}
/**
* Step frames
* @param frames Frame quantity to step
*/
public synchronized void step(int frames) {
if (player == null || frames == 0) {
return;
}
int desired = (getActualFrame() + frames) % framesTotal;
if (desired < 0) {
desired += framesTotal;
}
// skip desires frames
fpc.skip(desired - getActualFrame());
refreshDisplay();
}
/**
* Seek informed frame
* @param frame Frame to be sought
*/
public synchronized void seek(int frame) {
if (player == null || frame < 0 || frame >= framesTotal) {
return;
}
// skip desires frames
fpc.seek(frame);
refreshDisplay();
}
public void stop() {
synchronized (animator) {
animator.threadSuspend = true;
}
}
public void start() {
if (player == null) {
return;
}
if (animator.threadSuspend) {
synchronized (animator) {
animator.threadSuspend = false;
animator.notify();
}
}
}
public synchronized void close() {
setVideo(null);
}
public void reset() {
Video temp = video;
close();
setVideo(temp);
}
/**
* Set video to be played, if informed <code>null</code> reset player.
* If one is informed, the player leaves it video prefetched (ready to start)
* @param video Video to played or <code>null</code> to reset player
*/
public synchronized void setVideo(Video video) {
if (this.video == video) {
// video not changed
return;
}
this.video = video;
if (video == null) {
// doesn't present any video
stop();
player.close();
player = null;
ApolloUtil.gc();
return;
}
try {
Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, new Boolean(true));
// create player
MediaLocator locator = new MediaLocator(new URL("file", null, video.getCanonicalVideoFile()));
player = Manager.createProcessor(locator);
// configure processor
StateHelper helper = new StateHelper(player);
if (!helper.configure()) {
throw new RuntimeException("Failed to configure the player");
}
// can be uses as a player.
player.setContentDescriptor(null);
// search the track control for the video track.
TrackControl videoTrack = MediaUtil.getVideoTrack(player);
if (videoTrack == null) {
throw new RuntimeException("The input media does not contain a video track.");
}
videoTrack.setRenderer(renderer);
// retrieve a FramePositioningControl from the player.
fpc = (FramePositioningControl) player.getControl("javax.media.control.FramePositioningControl");
if (fpc == null) {
throw new RuntimeException("The player does not support FramePositioningControl.");
}
// prefetch player
if (!helper.prefetch(30000)) {
throw new RuntimeException("Failed to prefetch the player");
}
// get total frames info
Time duration = player.getDuration();
if (duration != Duration.DURATION_UNKNOWN) {
framesTotal = fpc.mapTimeToFrame(duration) + 1;
} else {
framesTotal = FramePositioningControl.FRAME_UNKNOWN;
}
refreshDisplay();
} catch (NoProcessorException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (NotConfiguredError e) {
throw new RuntimeException(e);
} catch (UnsupportedPlugInException e) {
throw new RuntimeException(e);
}
}
private final class Animator extends Thread {
protected volatile boolean threadSuspend = true;
public void run() {
while (true) {
try {
// code to suspend a thread safely
if (threadSuspend) {
synchronized (this) {
while (threadSuspend) {
wait();
}
}
}
step(1);
sleep((long) (1 / 25.0f * 1000));
} catch (InterruptedException e) {
// nop
}
}
}
}
}
|