// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.videomapping.video;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Window;
import java.util.LinkedList;
import java.util.List;
import org.openstreetmap.josm.Main;
import com.sun.jna.NativeLibrary;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.WinReg;
import uk.co.caprica.vlcj.binding.internal.libvlc_media_t;
import uk.co.caprica.vlcj.player.DeinterlaceMode;
import uk.co.caprica.vlcj.player.MediaPlayer;
import uk.co.caprica.vlcj.player.MediaPlayerEventListener;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.DefaultFullScreenStrategy;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.embedded.FullScreenStrategy;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
import uk.co.caprica.vlcj.runtime.windows.WindowsRuntimeUtil;
//concrete Player library that is able to playback multiple videos
public class VideoEngine implements MediaPlayerEventListener {
private FullScreenStrategy fullScreenStrategy;
public MediaPlayerFactory mediaPlayerFactory;
private List<Video> videos;
private List<VideosObserver> observers;
private final String[] libvlcArgs = {""};
private final String[] standardMediaOptions = {""};
private static final String[] deinterlacers = {"bob", "linear"};
//private final float initialCanvasFactor = 0.5f;
private boolean singleVideoMode; //commands will only affect the last added video
private Video lastAddedVideo;
//called at plugin start to setup library
public static void setupPlayer() {
String vlcInstallDir = null;
if (RuntimeUtil.isWindows()) {
vlcInstallDir = WindowsRuntimeUtil.getVlcInstallDir();
String arch = System.getProperty("os.arch");
if (vlcInstallDir == null && arch.equals("amd64")) {
try {
vlcInstallDir = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE,
WindowsRuntimeUtil.VLC_REGISTRY_KEY.replaceFirst("\\\\", "\\\\Wow6432Node\\\\"),
WindowsRuntimeUtil.VLC_INSTALL_DIR_KEY);
} catch (RuntimeException e) {
Main.error(e);
}
}
} else if (RuntimeUtil.isMac()) {
// TODO
} else if (RuntimeUtil.isNix()) {
// TODO
}
if (vlcInstallDir != null) {
Main.info("videomapping: found VLC install dir: "+vlcInstallDir);
NativeLibrary.addSearchPath("libvlc", vlcInstallDir);
} else {
Main.error("videomapping: unable to locate VLC install dir");
}
}
public VideoEngine(Window parent) {
System.setProperty("logj4.configuration", "file:log4j.xml"); //TODO still unsure if we can't link this to the JOSM log4j instance
videos = new LinkedList<>();
observers = new LinkedList<>();
try {
mediaPlayerFactory = new MediaPlayerFactory(libvlcArgs);
fullScreenStrategy = new DefaultFullScreenStrategy(parent);
} catch (NoClassDefFoundError e) {
Main.error(tr("Unable to find JNA Java library!"));
} catch (UnsatisfiedLinkError e) {
Main.error(tr("Unable to find native libvlc library!"));
} catch (Exception t) {
Main.error(t);
}
}
public void add(Video video) {
try {
EmbeddedMediaPlayer mp = mediaPlayerFactory.newEmbeddedMediaPlayer(fullScreenStrategy);
video.player = mp;
mp.setStandardMediaOptions(standardMediaOptions);
videos.add(video);
lastAddedVideo = video;
mp.setVideoSurface(video.videoSurface);
mp.addMediaPlayerEventListener(this);
String mediaPath = video.filename.getAbsoluteFile().toString();
mp.playMedia(mediaPath);
//now fetching and playback starts automatically
} catch (NoClassDefFoundError e) {
Main.error(tr("Unable to find JNA Java library!"));
} catch (UnsatisfiedLinkError e) {
Main.error(tr("Unable to find native libvlc library!"));
}
}
/*
private Video getVideo(MediaPlayer mp)
{
for (Video video : videos) {
if (video.player==mp) return video;
}
return null;
}
*/
public List<Video> getVideos() {
return videos;
}
public void play() {
if (singleVideoMode) {
lastAddedVideo.player.play();
} else {
for (Video video : videos) {
video.player.play();
}
}
}
//toggles pause and play
public void pause() {
if (singleVideoMode) {
lastAddedVideo.player.pause();
} else {
for (Video video : videos) {
video.player.pause();
}
}
}
//ensures that all stop
public void pauseAll() {
for (Video video : videos) {
if (video.player.isPlaying())
video.player.pause();
}
}
//jumps relative for ms in all videos
public void jumpFor(long ms) {
if (singleVideoMode) {
long start = lastAddedVideo.player.getTime();
lastAddedVideo.player.setTime(start+ms);
} else {
for (Video video : videos) {
long start = video.player.getTime();
video.player.setTime(start+ms);
}
}
notifyObservers(VideoObserversEvents.jumping);
}
//jumps in all videos to this absolute video time
public void jumpTo(long msVideo) {
if (singleVideoMode) {
lastAddedVideo.player.setTime(msVideo);
} else {
for (Video video : videos) {
video.player.setTime(msVideo);
}
}
notifyObservers(VideoObserversEvents.jumping);
}
//TODO muss evtl. auf Rückgabe für alle Videos erweitert werden
public long getVideoTime() {
return videos.get(0).player.getTime();
}
//jumps in all videos to this absolute video time percentage
public void jumpToPosition(int percent) {
float position = (percent/100f);
if (singleVideoMode) {
lastAddedVideo.player.setPosition(position);
} else {
for (Video video : videos) {
video.player.setPosition(position);
}
}
notifyObservers(VideoObserversEvents.jumping);
}
//TODO muss evtl. auf Rückgabe für alle Videos erweitert werden
public int getPosition() {
return (int) (videos.get(0).player.getPosition()*100);
}
public void setSpeed(int percent) {
if (singleVideoMode) {
lastAddedVideo.player.setRate(percent/100f);
}
for (Video video : videos) {
video.player.setRate(percent/100f);
}
notifyObservers(VideoObserversEvents.speeding);
}
//TODO muss evtl. auf Rückgabe für alle Videos erweitert werden
public int getSpeed() {
return (int) (videos.get(0).player.getRate()*100);
}
//returns if at least one video has subtitles
public boolean hasSubtitles() {
for (Video video : videos) {
if (video.player.getSpuCount() > 0) return true;
}
return false;
}
public void setSubtitles(boolean enabled) {
if (enabled) {
//VLC uses a list of sub picture units
for (Video video : videos) {
video.player.setSpu(0);
}
} else {
for (Video video : videos) {
video.player.setSpu(-1);
}
}
}
public void setDeinterlacer(DeinterlaceMode deinterlacer) {
if (singleVideoMode) {
lastAddedVideo.player.setDeinterlace(deinterlacer);
} else {
for (Video video : videos) {
video.player.setDeinterlace(deinterlacer);
}
}
}
public static String[] getDeinterlacers() {
return deinterlacers;
}
public void mute() {
if (singleVideoMode) {
lastAddedVideo.player.mute();
}
for (Video video : videos) {
video.player.mute();
}
}
public void unload() {
for (Video video : videos) {
video.player.stop();
video.player.release();
video.player = null;
video.videoSurface = null;
video.canvas = null;
}
mediaPlayerFactory.release();
}
public void addObserver(VideosObserver observer) {
observers.add(observer);
}
private void notifyObservers(VideoObserversEvents event) {
for (VideosObserver observer : observers) {
observer.update(event);
}
}
@Override
public void backward(MediaPlayer arg0) { }
/*
public void buffering(MediaPlayer arg0) {
}
*/
@Override
public void error(MediaPlayer arg0) { }
@Override
public void finished(MediaPlayer arg0) { }
@Override
public void forward(MediaPlayer arg0) { }
@Override
public void lengthChanged(MediaPlayer arg0, long arg1) { }
/*
public void mediaChanged(MediaPlayer arg0) {
}
public void metaDataAvailable(MediaPlayer mp, VideoMetaData data) {
Dimension org=data.getVideoDimension();
getVideo(mp).canvas.setSize(new Dimension((int)(org.width*initialCanvasFactor), (int)(org.height*initialCanvasFactor)));
notifyObservers(VideoObserversEvents.resizing);
}
*/
@Override
public void opening(MediaPlayer arg0) { }
@Override
public void pausableChanged(MediaPlayer arg0, int arg1) { }
@Override
public void paused(MediaPlayer arg0) { }
@Override
public void playing(MediaPlayer arg0) { }
@Override
public void positionChanged(MediaPlayer arg0, float arg1) { }
@Override
public void seekableChanged(MediaPlayer arg0, int arg1) { }
@Override
public void snapshotTaken(MediaPlayer arg0, String arg1) { }
@Override
public void stopped(MediaPlayer arg0) { }
@Override
public void timeChanged(MediaPlayer arg0, long arg1) { }
@Override
public void titleChanged(MediaPlayer arg0, int arg1) { }
public boolean isNoVideoPlaying() {
for (Video video : videos) {
if (video.player.isPlaying())
return false;
}
return true;
}
public void enableSingleVideoMode(boolean enabled) {
singleVideoMode = true;
}
@Override
public void mediaChanged(MediaPlayer mediaPlayer, libvlc_media_t media, String mrl) {
// TODO Auto-generated method stub
}
@Override
public void buffering(MediaPlayer mediaPlayer, float newCache) {
// TODO Auto-generated method stub
}
@Override
public void videoOutput(MediaPlayer mediaPlayer, int newCount) {
// TODO Auto-generated method stub
}
@Override
public void mediaMetaChanged(MediaPlayer mediaPlayer, int metaType) {
// TODO Auto-generated method stub
}
@Override
public void mediaSubItemAdded(MediaPlayer mediaPlayer, libvlc_media_t subItem) {
// TODO Auto-generated method stub
}
@Override
public void mediaDurationChanged(MediaPlayer mediaPlayer, long newDuration) {
// TODO Auto-generated method stub
}
@Override
public void mediaParsedChanged(MediaPlayer mediaPlayer, int newStatus) {
// TODO Auto-generated method stub
}
@Override
public void mediaFreed(MediaPlayer mediaPlayer) {
// TODO Auto-generated method stub
}
@Override
public void mediaStateChanged(MediaPlayer mediaPlayer, int newState) {
// TODO Auto-generated method stub
}
@Override
public void newMedia(MediaPlayer mediaPlayer) {
// TODO Auto-generated method stub
}
@Override
public void subItemPlayed(MediaPlayer mediaPlayer, int subItemIndex) {
// TODO Auto-generated method stub
}
@Override
public void subItemFinished(MediaPlayer mediaPlayer, int subItemIndex) {
// TODO Auto-generated method stub
}
@Override
public void endOfSubItems(MediaPlayer mediaPlayer) {
// TODO Auto-generated method stub
}
@Override
public void scrambledChanged(MediaPlayer mediaPlayer, int newScrambled) {
// TODO Auto-generated method stub
}
@Override
public void elementaryStreamAdded(MediaPlayer mediaPlayer, int type, int id) {
// TODO Auto-generated method stub
}
@Override
public void elementaryStreamDeleted(MediaPlayer mediaPlayer, int type, int id) {
// TODO Auto-generated method stub
}
@Override
public void elementaryStreamSelected(MediaPlayer mediaPlayer, int type, int id) {
// TODO Auto-generated method stub
}
@Override
public void corked(MediaPlayer mediaPlayer, boolean corked) {
// TODO Auto-generated method stub
}
@Override
public void muted(MediaPlayer mediaPlayer, boolean muted) {
// TODO Auto-generated method stub
}
@Override
public void volumeChanged(MediaPlayer mediaPlayer, float volume) {
// TODO Auto-generated method stub
}
@Override
public void audioDeviceChanged(MediaPlayer mediaPlayer, String audioDevice) {
// TODO Auto-generated method stub
}
@Override
public void chapterChanged(MediaPlayer mediaPlayer, int newChapter) {
// TODO Auto-generated method stub
}
@Override
public void mediaSubItemTreeAdded(MediaPlayer mediaPlayer, libvlc_media_t item) {
// TODO Auto-generated method stub
}
}