Browse Source

new media player based on vlcj [Part 2]

the new media player replaces the old one by now
dev
Jannik 2 years ago
parent
commit
a8160ce65e
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
  1. 115
      src/main/java/kellerkinder/HomeFlix/player/NewMediaPlayer.java
  2. 6
      src/main/java/kellerkinder/HomeFlix/player/Player.java
  3. 204
      src/main/java/kellerkinder/HomeFlix/player/PlayerController.java

115
src/main/java/kellerkinder/HomeFlix/player/NewMediaPlayer.java

@ -1,115 +0,0 @@
package kellerkinder.HomeFlix.player;
import java.nio.ByteBuffer;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelBuffer;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import kellerkinder.HomeFlix.application.Main;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.base.MediaPlayer;
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;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormat;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormatCallback;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.RenderCallback;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.format.RV32BufferFormat;
public class NewMediaPlayer {
private MediaPlayerFactory mediaPlayerFactory;
private EmbeddedMediaPlayer embeddedMediaPlayer;
private WritableImage videoImage;
private PixelBuffer<ByteBuffer> videoPixelBuffer;
private ImageView videoImageView;
private Stage stage;
private StackPane pane;
private Scene scene;
public NewMediaPlayer() {
mediaPlayerFactory = new MediaPlayerFactory();
embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
embeddedMediaPlayer.videoSurface().set(new FXCallbackVideoSurface());
}
public void init() {
// Auto-generated method stub
stage = new Stage();
pane = new StackPane();
scene = new Scene(pane);
videoImageView = new ImageView();
videoImageView.setPreserveRatio(true);
videoImageView.fitWidthProperty().bind(pane.widthProperty());
videoImageView.fitHeightProperty().bind(pane.heightProperty());
pane.getChildren().add(videoImageView);
stage.setScene(scene);
stage.setTitle("HomeFlix");
stage.getIcons().add(new Image(Main.class.getResourceAsStream("/icons/Homeflix_Icon_64x64.png")));
stage.setOnCloseRequest(event -> {
//DBController.getInstance().setCurrentTime(streamURL, playerController.getCurrentTime());
//playerController.getMediaPlayer().stop();
stop();
stage.close();
});
stage.show();
}
public void play(String streamURL) {
embeddedMediaPlayer.media().play(streamURL);
}
public void stop() {
embeddedMediaPlayer.controls().stop();
embeddedMediaPlayer.release();
mediaPlayerFactory.release();
System.out.println("released");
}
private class FXCallbackVideoSurface extends CallbackVideoSurface {
FXCallbackVideoSurface() {
super(new FXBufferFormatCallback(), new FXRenderCallback(), true,
VideoSurfaceAdapters.getVideoSurfaceAdapter());
}
}
private class FXBufferFormatCallback implements BufferFormatCallback {
private int sourceWidth;
private int sourceHeight;
@Override
public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) {
this.sourceWidth = sourceWidth;
this.sourceHeight = sourceHeight;
return new RV32BufferFormat(sourceWidth, sourceHeight);
}
@Override
public void allocatedBuffers(ByteBuffer[] buffers) {
assert buffers[0].capacity() == sourceWidth * sourceHeight * 4;
PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteBgraPreInstance();
videoPixelBuffer = new PixelBuffer<>(sourceWidth, sourceHeight, buffers[0], pixelFormat);
videoImage = new WritableImage(videoPixelBuffer);
videoImageView.setImage(videoImage);
}
}
private class FXRenderCallback implements RenderCallback {
@Override
public void display(MediaPlayer mediaPlayer, ByteBuffer[] nativeBuffers, BufferFormat bufferFormat) {
Platform.runLater(() -> {
videoPixelBuffer.updateBuffer(pb -> null);
});
}
}
}

6
src/main/java/kellerkinder/HomeFlix/player/Player.java

@ -81,14 +81,14 @@ public class Player {
stage.setTitle("HomeFlix");
stage.getIcons().add(new Image(Main.class.getResourceAsStream("/icons/Homeflix_Icon_64x64.png")));
stage.setOnCloseRequest(event -> {
playerController.stop2();
playerController.stop();
stage.close();
});
//stage.setFullScreen(true);
stage.show();
playerController.init2();
playerController.start2();
playerController.init();
playerController.start();
} catch (Exception e) {
e.printStackTrace();
}

204
src/main/java/kellerkinder/HomeFlix/player/PlayerController.java

@ -44,16 +44,14 @@ import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.util.Duration;
import kellerkinder.HomeFlix.controller.DBController;
import kellerkinder.HomeFlix.controller.XMLController;
import kellerkinder.HomeFlix.datatypes.FilmTabelDataType;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.base.MediaPlayer;
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;
@ -83,23 +81,20 @@ public class PlayerController {
@FXML private ImageView fullscreenIcon;
private Player player;
private Media media;
private MediaPlayer mediaPlayer2;
private MediaPlayerFactory mediaPlayerFactory;
private EmbeddedMediaPlayer embeddedMediaPlayer;
private WritableImage videoImage;
private PixelBuffer<ByteBuffer> videoPixelBuffer;
private FilmTabelDataType film;
private long currentTime = 0;
private long seekTime = 0;
private long startTime = 0;
private long currentTime = 0;
private long endTime = 0;
private long skipTime = 0;
private long duration = 0;
private int season = 0;
private int episode = 0;
private int countdown = 0;
private boolean mousePressed = false;
private boolean showControls = true;
private boolean autoplay;
@ -111,20 +106,19 @@ public class PlayerController {
/**
* create a new PlayerWindow object
* @param mainWCon the MainWindowController TODO do we need this?
* @param player the player object (needed for closing action)
* @param film the film object
*/
public PlayerController(Player player, String streamURL) {
public PlayerController(Player player, String mediaURL) {
this.player = player;
this.film = DBController.getInstance().getStream(streamURL);
this.film = DBController.getInstance().getStream(mediaURL);
mediaPlayerFactory = new MediaPlayerFactory();
embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
embeddedMediaPlayer.videoSurface().set(new FXCallbackVideoSurface());
}
public void init2() {
public void init() {
// initialize the image view
videoImageView.setPreserveRatio(true);
videoImageView.fitWidthProperty().bind(player.getStage().widthProperty());
@ -136,114 +130,71 @@ public class PlayerController {
season = !film.getSeason().isEmpty() ? Integer.parseInt(film.getSeason()) : 0;
episode = !film.getEpisode().isEmpty() ? Integer.parseInt(film.getEpisode()) : 0;
initActions2();
initPlayerWindow();
initMediaPlayer();
initSlider();
}
private void initActions2() {
private void initMediaPlayer() {
embeddedMediaPlayer.events().addMediaPlayerEventListener( new HFMediaPlayerEventListener() {
@Override
public void timeChanged(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, long newTime) {
timeSlider.setValue((newTime / 1000) / 60);
public void timeChanged(MediaPlayer mediaPlayer, long newTime) {
currentTime = newTime;
endTime = duration - newTime;
Platform.runLater(() -> {
updateControls();
});
}
@Override
public void error(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
public void error(MediaPlayer mediaPlayer) {
// Auto-generated method stub
}
@Override
public void lengthChanged(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, long newLength) {
public void lengthChanged(MediaPlayer mediaPlayer, long newLength) {
duration = newLength;
timeSlider.setMax((duration / 1000) / 60);
timeSlider.setMax((duration / 1000) / 60); // TODO move timeslider to seconds
}
});
}
public void start2() {
embeddedMediaPlayer.media().play(film.getStreamUrl());
embeddedMediaPlayer.controls().skipTime((long) startTime);
}
public void stop2() {
DBController.getInstance().setCurrentTime(film.getStreamUrl(), embeddedMediaPlayer.status().time());
embeddedMediaPlayer.controls().stop();
embeddedMediaPlayer.release();
mediaPlayerFactory.release();
}
/**
* initialize the PlayerWindow
*/
public void init() {
initActions();
initMediaPlayer();
}
private void initMediaPlayer() {
// start the media if the player is ready
mediaPlayer2.setOnReady(new Runnable() {
private void initSlider() {
// if the mouse on the timeSlider is released, skip to the new position
timeSlider.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void run() {
duration = (long) media.getDuration().toMillis();
timeSlider.setMax((duration / 1000) / 60);
mediaPlayer2.play();
mediaPlayer2.seek(Duration.millis(startTime));
public void handle(MouseEvent event) {
embeddedMediaPlayer.controls().skipTime(skipTime);
mousePressed = false;
}
});
// every time the play time changes execute this
mediaPlayer2.currentTimeProperty().addListener(new ChangeListener<Duration>() {
timeSlider.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
currentTime = (long) newValue.toMillis(); // set the current time
double timeToEnd = (duration - currentTime);
if (timeToEnd < 20000 && episode != 0 && autoplay) {
// show 20 seconds before the end a button (next episode in 10 seconds)
if (!nextEpBtn.isVisible())
nextEpBtn.setVisible(true);
if (countdown != (int) ((timeToEnd - 10000) / 1000)) {
countdown = (int) ((timeToEnd - 10000) / 1000);
nextEpBtn.setText("next episode in " + countdown + " seconds"); // TODO translate
bottomVBox.setVisible(true);
}
// if we are end time -10 seconds, do autoplay, if activated
if (timeToEnd < 10000) {
nextEpBtn.setVisible(false);
autoPlayNewFilm();
}
} else if (timeToEnd < 120) {
// if we are 120ms to the end stop the media
mediaPlayer2.stop();
DBController.getInstance().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time
playIcon.setImage(playArrow);
} else {
if (nextEpBtn.isVisible())
nextEpBtn.setVisible(false);
}
if (!mousePressed) {
timeSlider.setValue((currentTime / 1000) / 60);
}
public void handle(MouseEvent event) {
mousePressed = true;
}
});
// get the new skip time
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);
}
});
}
/**
* initialize some PlayerWindow GUI-Elements actions
*/
private void initActions() {
private void initPlayerWindow() {
player.getScene().addEventFilter(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>() {
// hide controls timer initialization
final Timer timer = new Timer();
TimerTask controlAnimationTask = null; // task to execute save operation
@ -273,35 +224,55 @@ public class PlayerController {
timer.schedule(controlAnimationTask, delayTime);
}
});
// if the mouse on the timeSlider is released seek to the new position
timeSlider.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
mediaPlayer2.seek(new Duration(seekTime));
mousePressed = false;
}
});
timeSlider.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
mousePressed = true;
}
public void start() {
embeddedMediaPlayer.media().play(film.getStreamUrl());
embeddedMediaPlayer.controls().skipTime((long) startTime); // skipt to the start time
}
public void stop() {
DBController.getInstance().setCurrentTime(film.getStreamUrl(), embeddedMediaPlayer.status().time());
embeddedMediaPlayer.controls().stop();
embeddedMediaPlayer.release();
mediaPlayerFactory.release();
}
/**
* call this every second to update all timers
*/
private void updateControls() {
// update slider position, if the mouse does not press on the time
if (!mousePressed) {
timeSlider.setValue((currentTime / 1000) / 60);
}
// TODO update endTime label
System.out.println(endTime / 1000);
// show the next episode button 20 seconds before the end of a episode
if (endTime < 21000 && episode != 0 && autoplay) {
int countdown = (int) ((endTime / 1000) - 10); // a 10 seconds countdown
if (!nextEpBtn.isVisible()) {
nextEpBtn.setVisible(true);
}
});
// get the new seek time
timeSlider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> ov, Number old_val, Number new_val) {
seekTime = (long) ((double) new_val * 1000 * 60);
if (endTime > 10000) {
nextEpBtn.setText("next episode in " + countdown + " seconds"); // TODO translate
bottomVBox.setVisible(true);
System.out.println("next episode in " + countdown + " seconds");
} else {
nextEpBtn.setVisible(false);
// TODO start next episode
System.out.println("playing next episode ...");
}
});
}
}
@FXML
void stopBtnAction(ActionEvent event) {
stop2();
stop();
player.getStage().close();
}
@ -329,7 +300,7 @@ public class PlayerController {
@FXML
void nextEpBtnAction(ActionEvent event) {
autoPlayNewFilm();
autoPlayNewFilm(); // TODO
}
private void autoPlayNewFilm() {
@ -337,17 +308,12 @@ public class PlayerController {
DBController.getInstance().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time
FilmTabelDataType nextFilm = DBController.getInstance().getNextEpisode(film.getTitle(), episode, season);
if (nextFilm != null) {
mediaPlayer2.stop();
//mediaPlayer2.stop();
film = nextFilm;
init();
autoplay = true;
}
}
public MediaPlayer getMediaPlayer() {
return mediaPlayer2;
}
public double getCurrentTime() {
return currentTime;
}

Loading…
Cancel
Save

Du besuchst diese Seite mit einem veralteten IPv4-Internetzugang. Möglicherweise treten in Zukunft Probleme mit der Erreichbarkeit und Performance auf. Bitte frage deinen Internetanbieter oder Netzwerkadministrator nach IPv6-Unterstützung.
You are visiting this site with an outdated IPv4 internet access. You may experience problems with accessibility and performance in the future. Please ask your ISP or network administrator for IPv6 support.
Weitere Infos | More Information
Klicke zum schließen | Click to close