|
|
|
@@ -23,6 +23,8 @@
|
|
|
|
|
package org.mosad.homeflix.player;
|
|
|
|
|
|
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Timer;
|
|
|
|
|
import java.util.TimerTask;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
@@ -33,6 +35,7 @@ import org.mosad.homeflix.datatypes.FilmTabelDataType;
|
|
|
|
|
|
|
|
|
|
import com.jfoenix.controls.JFXButton;
|
|
|
|
|
import com.jfoenix.controls.JFXDialogLayout;
|
|
|
|
|
import com.jfoenix.controls.JFXListView;
|
|
|
|
|
import com.jfoenix.controls.JFXPopup;
|
|
|
|
|
import com.jfoenix.controls.JFXPopup.PopupHPosition;
|
|
|
|
|
import com.jfoenix.controls.JFXPopup.PopupVPosition;
|
|
|
|
@@ -44,6 +47,7 @@ import javafx.beans.value.ObservableValue;
|
|
|
|
|
import javafx.event.ActionEvent;
|
|
|
|
|
import javafx.event.EventHandler;
|
|
|
|
|
import javafx.fxml.FXML;
|
|
|
|
|
import javafx.geometry.Insets;
|
|
|
|
|
import javafx.scene.Cursor;
|
|
|
|
|
import javafx.scene.control.Label;
|
|
|
|
|
import javafx.scene.image.Image;
|
|
|
|
@@ -54,11 +58,14 @@ import javafx.scene.image.WritableImage;
|
|
|
|
|
import javafx.scene.input.MouseEvent;
|
|
|
|
|
import javafx.scene.layout.AnchorPane;
|
|
|
|
|
import javafx.scene.layout.HBox;
|
|
|
|
|
import javafx.scene.layout.Pane;
|
|
|
|
|
import javafx.scene.layout.VBox;
|
|
|
|
|
import javafx.scene.media.MediaView;
|
|
|
|
|
import javafx.scene.text.Text;
|
|
|
|
|
import javafx.util.StringConverter;
|
|
|
|
|
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
|
|
|
|
|
import uk.co.caprica.vlcj.player.base.MediaPlayer;
|
|
|
|
|
import uk.co.caprica.vlcj.player.base.TrackDescription;
|
|
|
|
|
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
|
|
|
|
|
import uk.co.caprica.vlcj.player.embedded.videosurface.CallbackVideoSurface;
|
|
|
|
|
import uk.co.caprica.vlcj.player.embedded.videosurface.VideoSurfaceAdapters;
|
|
|
|
@@ -107,6 +114,8 @@ public class PlayerController {
|
|
|
|
|
private long endTime = 0;
|
|
|
|
|
private long skipTime = 0;
|
|
|
|
|
private long duration = 0;
|
|
|
|
|
private List<TrackDescription> tracks = new ArrayList<>();
|
|
|
|
|
private int currentTrack = 0;
|
|
|
|
|
|
|
|
|
|
private int season = 0;
|
|
|
|
|
private int episode = 0;
|
|
|
|
@@ -119,6 +128,8 @@ public class PlayerController {
|
|
|
|
|
private Image fullscreen = new Image("icons/baseline_fullscreen_white_48dp.png");
|
|
|
|
|
private Image fullscreenExit = new Image("icons/baseline_fullscreen_exit_white_48dp.png");
|
|
|
|
|
|
|
|
|
|
private JFXPopup audioPopup;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* create a new PlayerWindow object
|
|
|
|
|
* @param player the player object (needed for closing action)
|
|
|
|
@@ -150,6 +161,11 @@ public class PlayerController {
|
|
|
|
|
initPlayerWindow();
|
|
|
|
|
initMediaPlayer();
|
|
|
|
|
initTimeSlider();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pane thumb = (Pane) timeSlider.lookup(".thumb");
|
|
|
|
|
System.out.println(thumb.getChildren());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -162,11 +178,11 @@ public class PlayerController {
|
|
|
|
|
// hide controls timer initialization
|
|
|
|
|
final Timer timer = new Timer();
|
|
|
|
|
TimerTask controlAnimationTask = null; // task to execute save operation
|
|
|
|
|
final long delayTime = 3000; // hide the controls after 2 seconds
|
|
|
|
|
final long delayTime = 4000; // hide the controls after 2 seconds
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void handle(MouseEvent mouseEvent) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// show controls
|
|
|
|
|
if (!showControls) {
|
|
|
|
|
player.getScene().setCursor(Cursor.DEFAULT);
|
|
|
|
@@ -181,6 +197,7 @@ public class PlayerController {
|
|
|
|
|
controlAnimationTask = new TimerTask() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
// TODO a animation would be nice
|
|
|
|
|
hBoxTop.setVisible(false);
|
|
|
|
|
bottomVBox.setVisible(false);
|
|
|
|
|
player.getScene().setCursor(Cursor.NONE);
|
|
|
|
@@ -200,12 +217,8 @@ public class PlayerController {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void mediaPlayerReady(MediaPlayer mediaPlayer) {
|
|
|
|
|
System.out.println(mediaPlayer.audio().trackCount());
|
|
|
|
|
|
|
|
|
|
mediaPlayer.audio().trackDescriptions().forEach(trackDesc -> {
|
|
|
|
|
System.out.println(trackDesc.description());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tracks = mediaPlayer.audio().trackDescriptions();
|
|
|
|
|
currentTrack = mediaPlayer.audio().track();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@@ -226,7 +239,7 @@ public class PlayerController {
|
|
|
|
|
@Override
|
|
|
|
|
public void lengthChanged(MediaPlayer mediaPlayer, long newLength) {
|
|
|
|
|
duration = newLength;
|
|
|
|
|
timeSlider.setMax((duration / 1000) / 60); // TODO move timeslider to seconds
|
|
|
|
|
timeSlider.setMax(duration / 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
@@ -256,9 +269,38 @@ public class PlayerController {
|
|
|
|
|
timeSlider.valueProperty().addListener(new ChangeListener<Number>() {
|
|
|
|
|
@Override
|
|
|
|
|
public void changed(ObservableValue<? extends Number> ov, Number old_val, Number new_val) {
|
|
|
|
|
skipTime = ((new_val.longValue() * 1000 * 60) - currentTime);
|
|
|
|
|
skipTime = ((new_val.longValue() * 1000) - currentTime);
|
|
|
|
|
//System.out.println(timeSlider.getChildrenUnmodifiable());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
timeSlider.setOnMouseMoved(new EventHandler<MouseEvent>() {
|
|
|
|
|
@Override
|
|
|
|
|
public void handle(MouseEvent event) {
|
|
|
|
|
//System.out.println("TEST");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// show h:mm:ss in the animated thumb
|
|
|
|
|
StringConverter<Double> convert = new StringConverter<Double>() {
|
|
|
|
|
@Override
|
|
|
|
|
public String toString(Double object) {
|
|
|
|
|
long time = object.longValue();
|
|
|
|
|
|
|
|
|
|
return String.format("%d:%02d:%02d", TimeUnit.SECONDS.toHours(time) % 24,
|
|
|
|
|
TimeUnit.SECONDS.toMinutes(time) % 60, TimeUnit.SECONDS.toSeconds(time) % 60);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Double fromString(String string) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
timeSlider.setLabelFormatter(convert);
|
|
|
|
|
|
|
|
|
|
// TODO add a preview to the animated thumb, if that's possible
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void start() {
|
|
|
|
@@ -283,7 +325,7 @@ public class PlayerController {
|
|
|
|
|
private void updateControls() {
|
|
|
|
|
// update slider position, if the mouse does not press on the time
|
|
|
|
|
if (!mousePressed) {
|
|
|
|
|
timeSlider.setValue((currentTime / 1000) / 60);
|
|
|
|
|
timeSlider.setValue(currentTime / 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// update endTime label
|
|
|
|
@@ -341,17 +383,38 @@ public class PlayerController {
|
|
|
|
|
|
|
|
|
|
@FXML
|
|
|
|
|
void btnAudioAction(ActionEvent event) {
|
|
|
|
|
// TODO move to separate class "AudioPopup"
|
|
|
|
|
|
|
|
|
|
JFXDialogLayout content = new JFXDialogLayout();
|
|
|
|
|
content.setHeading(new Text("Test"));
|
|
|
|
|
content.setBody(new Text("Hallo 123"));
|
|
|
|
|
content.setPrefSize(150, 200);
|
|
|
|
|
|
|
|
|
|
JFXPopup popup = new JFXPopup();
|
|
|
|
|
popup.setPopupContent(content);
|
|
|
|
|
popup.show(btnAudio, PopupVPosition.BOTTOM, PopupHPosition.RIGHT,
|
|
|
|
|
0, -1 * bottomVBox.getHeight());
|
|
|
|
|
if (audioPopup == null) {
|
|
|
|
|
audioPopup = new JFXPopup();
|
|
|
|
|
|
|
|
|
|
JFXListView<String> list = new JFXListView<String>();
|
|
|
|
|
tracks.forEach(track -> {
|
|
|
|
|
list.getItems().add(track.description());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
list.getSelectionModel().select(currentTrack);
|
|
|
|
|
list.setOnMouseClicked(ev -> {
|
|
|
|
|
setAudioTrack(list.getSelectionModel().getSelectedIndex());
|
|
|
|
|
audioPopup.hide();
|
|
|
|
|
});
|
|
|
|
|
// TODO style the JFXListView
|
|
|
|
|
|
|
|
|
|
JFXDialogLayout content = new JFXDialogLayout();
|
|
|
|
|
content.setPrefSize(150, 200);
|
|
|
|
|
content.setHeading(new Text("Audio"));
|
|
|
|
|
content.setBody(list);
|
|
|
|
|
content.setPadding(new Insets(-20, -20, -20, -20)); // fix JFXDialogLayout padding
|
|
|
|
|
content.setSpacing(-10); // fix JFXDialogLayout spacing
|
|
|
|
|
|
|
|
|
|
audioPopup.setPopupContent(content);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!audioPopup.isShowing()) {
|
|
|
|
|
// TODO this does not work properly
|
|
|
|
|
audioPopup.show(btnAudio, PopupVPosition.BOTTOM, PopupHPosition.RIGHT,
|
|
|
|
|
0, -1 * bottomVBox.getHeight());
|
|
|
|
|
} else {
|
|
|
|
|
audioPopup.hide();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@FXML
|
|
|
|
@@ -371,6 +434,9 @@ public class PlayerController {
|
|
|
|
|
playNextMedia();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* play the next media
|
|
|
|
|
*/
|
|
|
|
|
private void playNextMedia() {
|
|
|
|
|
autoplay = false;
|
|
|
|
|
DBController.getInstance().setCurrentTime(media.getStreamUrl(), 0); // reset old video start time
|
|
|
|
@@ -381,6 +447,15 @@ public class PlayerController {
|
|
|
|
|
autoplay = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* change the audio track
|
|
|
|
|
* @param track the index of the audio track
|
|
|
|
|
*/
|
|
|
|
|
private void setAudioTrack(int track) {
|
|
|
|
|
embeddedMediaPlayer.audio().setTrack(track);
|
|
|
|
|
currentTrack = track;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public double getCurrentTime() {
|
|
|
|
|
return currentTime;
|
|
|
|
|