new media player based on vlcj [Part 1]
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
* openjfx 12.0.2 -> 14 * log4j 2.13.0 -> 2.13.1 * maven-shade-plugin 3.2.1 -> 3.2.2
This commit is contained in:
parent
ef5d87c54c
commit
4184e982ea
18
pom.xml
18
pom.xml
|
@ -27,19 +27,25 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>12.0.2</version>
|
<version>14</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>12.0.2</version>
|
<version>14</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-media</artifactId>
|
<artifactId>javafx-media</artifactId>
|
||||||
<version>12.0.2</version>
|
<version>14</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>uk.co.caprica</groupId>
|
||||||
|
<artifactId>vlcj</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -69,13 +75,13 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-api</artifactId>
|
<artifactId>log4j-api</artifactId>
|
||||||
<version>2.13.0</version>
|
<version>2.13.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
<version>2.13.0</version>
|
<version>2.13.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -114,7 +120,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>3.2.1</version>
|
<version>3.2.2</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<finalName>Project-HomeFlix</finalName>
|
<finalName>Project-HomeFlix</finalName>
|
||||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
|
|
|
@ -47,6 +47,8 @@ public class Main extends Application {
|
||||||
public static final String buildNumber = "173";
|
public static final String buildNumber = "173";
|
||||||
public static final String versionName = "toothless dragon";
|
public static final String versionName = "toothless dragon";
|
||||||
|
|
||||||
|
// TODO rename streamURL to mediaURL
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws IOException {
|
public void start(Stage primaryStage) throws IOException {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
/**
|
||||||
|
* Project-HomeFlix
|
||||||
|
*
|
||||||
|
* Copyright 2016-2020 <seil0@mosad.xyz>
|
||||||
|
*
|
||||||
|
* 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 3 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package kellerkinder.HomeFlix.player;
|
||||||
|
|
||||||
|
import uk.co.caprica.vlcj.media.MediaRef;
|
||||||
|
import uk.co.caprica.vlcj.media.TrackType;
|
||||||
|
import uk.co.caprica.vlcj.player.base.MediaPlayer;
|
||||||
|
import uk.co.caprica.vlcj.player.base.MediaPlayerEventListener;
|
||||||
|
|
||||||
|
public class HFMediaPlayerEventListener implements MediaPlayerEventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mediaChanged(MediaPlayer mediaPlayer, MediaRef media) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void opening(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buffering(MediaPlayer mediaPlayer, float newCache) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playing(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paused(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopped(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forward(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void backward(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finished(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void timeChanged(MediaPlayer mediaPlayer, long newTime) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void positionChanged(MediaPlayer mediaPlayer, float newPosition) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekableChanged(MediaPlayer mediaPlayer, int newSeekable) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pausableChanged(MediaPlayer mediaPlayer, int newPausable) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void titleChanged(MediaPlayer mediaPlayer, int newTitle) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void snapshotTaken(MediaPlayer mediaPlayer, String filename) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lengthChanged(MediaPlayer mediaPlayer, long newLength) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void videoOutput(MediaPlayer mediaPlayer, int newCount) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scrambledChanged(MediaPlayer mediaPlayer, int newScrambled) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void elementaryStreamAdded(MediaPlayer mediaPlayer, TrackType type, int id) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void elementaryStreamDeleted(MediaPlayer mediaPlayer, TrackType type, int id) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void elementaryStreamSelected(MediaPlayer mediaPlayer, TrackType type, int id) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void corked(MediaPlayer mediaPlayer, boolean corked) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void muted(MediaPlayer mediaPlayer, boolean muted) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void volumeChanged(MediaPlayer mediaPlayer, float volume) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void audioDeviceChanged(MediaPlayer mediaPlayer, String audioDevice) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void chapterChanged(MediaPlayer mediaPlayer, int newChapter) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mediaPlayerReady(MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Project-HomeFlix
|
* Project-HomeFlix
|
||||||
*
|
*
|
||||||
* Copyright 2016-2019 <@Seil0>
|
* Copyright 2016-2020 <seil0@mosad.xyz>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -36,9 +36,10 @@ import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import kellerkinder.HomeFlix.application.Main;
|
import kellerkinder.HomeFlix.application.Main;
|
||||||
import kellerkinder.HomeFlix.controller.DBController;
|
|
||||||
public class Player {
|
public class Player {
|
||||||
|
|
||||||
private PlayerController playerController;
|
private PlayerController playerController;
|
||||||
|
@ -54,21 +55,20 @@ public class Player {
|
||||||
* @param currentTableFilm the currently selected film
|
* @param currentTableFilm the currently selected film
|
||||||
*/
|
*/
|
||||||
public Player(String streamURL) {
|
public Player(String streamURL) {
|
||||||
|
try {
|
||||||
if (isSupportedFormat(streamURL)) {
|
newHFPlayer(streamURL);
|
||||||
hfPlayer(streamURL);
|
} catch (Exception e) {
|
||||||
} else {
|
LOGGER.error("Error while playing media", e);
|
||||||
legacyPlayer(streamURL);
|
legacyPlayer(streamURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* start the integrated player
|
* start the integrated player
|
||||||
* @param streamURL
|
* @param streamURL
|
||||||
*/
|
*/
|
||||||
private void hfPlayer(String streamURL) {
|
private void newHFPlayer(String mediaURL) {
|
||||||
playerController = new PlayerController(this, streamURL);
|
playerController = new PlayerController(this, mediaURL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader();
|
FXMLLoader fxmlLoader = new FXMLLoader();
|
||||||
|
@ -81,15 +81,14 @@ public class Player {
|
||||||
stage.setTitle("HomeFlix");
|
stage.setTitle("HomeFlix");
|
||||||
stage.getIcons().add(new Image(Main.class.getResourceAsStream("/icons/Homeflix_Icon_64x64.png")));
|
stage.getIcons().add(new Image(Main.class.getResourceAsStream("/icons/Homeflix_Icon_64x64.png")));
|
||||||
stage.setOnCloseRequest(event -> {
|
stage.setOnCloseRequest(event -> {
|
||||||
DBController.getInstance().setCurrentTime(streamURL, playerController.getCurrentTime());
|
playerController.stop2();
|
||||||
playerController.getMediaPlayer().stop();
|
|
||||||
stage.close();
|
stage.close();
|
||||||
});
|
});
|
||||||
|
//stage.setFullScreen(true);
|
||||||
playerController.init();
|
|
||||||
|
|
||||||
stage.setFullScreen(true);
|
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|
||||||
|
playerController.init2();
|
||||||
|
playerController.start2();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -158,4 +157,8 @@ public class Player {
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Pane getPane() {
|
||||||
|
return pane;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Project-HomeFlix
|
* Project-HomeFlix
|
||||||
*
|
*
|
||||||
* Copyright 2016-2019 <@Seil0>
|
* Copyright 2016-2020 <seil0@mosad.xyz>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -22,15 +22,14 @@
|
||||||
|
|
||||||
package kellerkinder.HomeFlix.player;
|
package kellerkinder.HomeFlix.player;
|
||||||
|
|
||||||
import java.io.File;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXSlider;
|
import com.jfoenix.controls.JFXSlider;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.DoubleProperty;
|
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
|
@ -39,21 +38,34 @@ import javafx.fxml.FXML;
|
||||||
import javafx.scene.Cursor;
|
import javafx.scene.Cursor;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.image.PixelBuffer;
|
||||||
|
import javafx.scene.image.PixelFormat;
|
||||||
|
import javafx.scene.image.WritableImage;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.media.Media;
|
import javafx.scene.media.Media;
|
||||||
import javafx.scene.media.MediaPlayer;
|
import javafx.scene.media.MediaPlayer;
|
||||||
import javafx.scene.media.MediaPlayer.Status;
|
|
||||||
import javafx.scene.media.MediaView;
|
import javafx.scene.media.MediaView;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
|
||||||
import kellerkinder.HomeFlix.controller.DBController;
|
import kellerkinder.HomeFlix.controller.DBController;
|
||||||
import kellerkinder.HomeFlix.controller.XMLController;
|
import kellerkinder.HomeFlix.controller.XMLController;
|
||||||
import kellerkinder.HomeFlix.datatypes.FilmTabelDataType;
|
import kellerkinder.HomeFlix.datatypes.FilmTabelDataType;
|
||||||
|
|
||||||
|
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
|
||||||
|
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 PlayerController {
|
public class PlayerController {
|
||||||
|
|
||||||
@FXML private MediaView mediaView;
|
@FXML private MediaView mediaView;
|
||||||
|
@FXML private ImageView videoImageView;
|
||||||
|
|
||||||
@FXML private VBox bottomVBox;
|
@FXML private VBox bottomVBox;
|
||||||
|
|
||||||
|
@ -72,13 +84,19 @@ public class PlayerController {
|
||||||
|
|
||||||
private Player player;
|
private Player player;
|
||||||
private Media media;
|
private Media media;
|
||||||
private MediaPlayer mediaPlayer;
|
private MediaPlayer mediaPlayer2;
|
||||||
|
|
||||||
|
private MediaPlayerFactory mediaPlayerFactory;
|
||||||
|
private EmbeddedMediaPlayer embeddedMediaPlayer;
|
||||||
|
private WritableImage videoImage;
|
||||||
|
private PixelBuffer<ByteBuffer> videoPixelBuffer;
|
||||||
|
|
||||||
private FilmTabelDataType film;
|
private FilmTabelDataType film;
|
||||||
private double currentTime = 0;
|
private long currentTime = 0;
|
||||||
private double seekTime = 0;
|
private long seekTime = 0;
|
||||||
private double startTime = 0;
|
private long startTime = 0;
|
||||||
private double duration = 0;
|
private long duration = 0;
|
||||||
|
|
||||||
private int season = 0;
|
private int season = 0;
|
||||||
private int episode = 0;
|
private int episode = 0;
|
||||||
private int countdown = 0;
|
private int countdown = 0;
|
||||||
|
@ -100,62 +118,90 @@ public class PlayerController {
|
||||||
public PlayerController(Player player, String streamURL) {
|
public PlayerController(Player player, String streamURL) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.film = DBController.getInstance().getStream(streamURL);
|
this.film = DBController.getInstance().getStream(streamURL);
|
||||||
|
|
||||||
|
mediaPlayerFactory = new MediaPlayerFactory();
|
||||||
|
embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
|
||||||
|
embeddedMediaPlayer.videoSurface().set(new FXCallbackVideoSurface());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init2() {
|
||||||
|
// initialize the image view
|
||||||
|
videoImageView.setPreserveRatio(true);
|
||||||
|
videoImageView.fitWidthProperty().bind(player.getStage().widthProperty());
|
||||||
|
videoImageView.fitHeightProperty().bind(player.getStage().heightProperty());
|
||||||
|
|
||||||
|
// set needed variables
|
||||||
|
startTime = (long) DBController.getInstance().getCurrentTime(film.getStreamUrl());
|
||||||
|
autoplay = XMLController.isAutoplay();
|
||||||
|
season = !film.getSeason().isEmpty() ? Integer.parseInt(film.getSeason()) : 0;
|
||||||
|
episode = !film.getEpisode().isEmpty() ? Integer.parseInt(film.getEpisode()) : 0;
|
||||||
|
|
||||||
|
initActions2();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initActions2() {
|
||||||
|
embeddedMediaPlayer.events().addMediaPlayerEventListener( new HFMediaPlayerEventListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void timeChanged(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, long newTime) {
|
||||||
|
timeSlider.setValue((newTime / 1000) / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
|
||||||
|
// Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lengthChanged(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, long newLength) {
|
||||||
|
duration = newLength;
|
||||||
|
timeSlider.setMax((duration / 1000) / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* initialize the PlayerWindow
|
||||||
*/
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
initActions();
|
initActions();
|
||||||
|
|
||||||
if (film.getStreamUrl().startsWith("http")) {
|
|
||||||
media = new Media(film.getStreamUrl());
|
|
||||||
} else {
|
|
||||||
media = new Media(new File(film.getStreamUrl()).toURI().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the MediaPlayer object
|
|
||||||
mediaPlayer = new MediaPlayer(media);
|
|
||||||
mediaView.setPreserveRatio(true);
|
|
||||||
mediaView.setMediaPlayer(mediaPlayer);
|
|
||||||
|
|
||||||
final DoubleProperty width = mediaView.fitWidthProperty();
|
|
||||||
final DoubleProperty height = mediaView.fitHeightProperty();
|
|
||||||
|
|
||||||
width.bind(Bindings.selectDouble(mediaView.sceneProperty(), "width"));
|
|
||||||
height.bind(Bindings.selectDouble(mediaView.sceneProperty(), "height"));
|
|
||||||
|
|
||||||
startTime = DBController.getInstance().getCurrentTime(film.getStreamUrl());
|
|
||||||
autoplay = XMLController.isAutoplay();
|
|
||||||
season = !film.getSeason().isEmpty() ? Integer.parseInt(film.getSeason()) : 0;
|
|
||||||
episode = !film.getEpisode().isEmpty() ? Integer.parseInt(film.getEpisode()) : 0;
|
|
||||||
|
|
||||||
initMediaPlayer();
|
initMediaPlayer();
|
||||||
|
|
||||||
// set the control elements to the correct value
|
|
||||||
playIcon.setImage(pause);
|
|
||||||
fullscreenIcon.setImage(fullscreenExit);
|
|
||||||
timeSlider.setValue(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initMediaPlayer() {
|
private void initMediaPlayer() {
|
||||||
// start the media if the player is ready
|
// start the media if the player is ready
|
||||||
mediaPlayer.setOnReady(new Runnable() {
|
mediaPlayer2.setOnReady(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
duration = media.getDuration().toMillis();
|
duration = (long) media.getDuration().toMillis();
|
||||||
timeSlider.setMax((duration / 1000) / 60);
|
timeSlider.setMax((duration / 1000) / 60);
|
||||||
|
|
||||||
mediaPlayer.play();
|
mediaPlayer2.play();
|
||||||
mediaPlayer.seek(Duration.millis(startTime));
|
mediaPlayer2.seek(Duration.millis(startTime));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// every time the play time changes execute this
|
// every time the play time changes execute this
|
||||||
mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>() {
|
mediaPlayer2.currentTimeProperty().addListener(new ChangeListener<Duration>() {
|
||||||
@Override
|
@Override
|
||||||
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
|
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
|
||||||
currentTime = newValue.toMillis(); // set the current time
|
currentTime = (long) newValue.toMillis(); // set the current time
|
||||||
double timeToEnd = (duration - currentTime);
|
double timeToEnd = (duration - currentTime);
|
||||||
|
|
||||||
if (timeToEnd < 20000 && episode != 0 && autoplay) {
|
if (timeToEnd < 20000 && episode != 0 && autoplay) {
|
||||||
|
@ -176,7 +222,7 @@ public class PlayerController {
|
||||||
}
|
}
|
||||||
} else if (timeToEnd < 120) {
|
} else if (timeToEnd < 120) {
|
||||||
// if we are 120ms to the end stop the media
|
// if we are 120ms to the end stop the media
|
||||||
mediaPlayer.stop();
|
mediaPlayer2.stop();
|
||||||
DBController.getInstance().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time
|
DBController.getInstance().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time
|
||||||
playIcon.setImage(playArrow);
|
playIcon.setImage(playArrow);
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,7 +278,7 @@ public class PlayerController {
|
||||||
timeSlider.setOnMouseReleased(new EventHandler<MouseEvent>() {
|
timeSlider.setOnMouseReleased(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent event) {
|
public void handle(MouseEvent event) {
|
||||||
mediaPlayer.seek(new Duration(seekTime));
|
mediaPlayer2.seek(new Duration(seekTime));
|
||||||
mousePressed = false;
|
mousePressed = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -248,15 +294,14 @@ public class PlayerController {
|
||||||
timeSlider.valueProperty().addListener(new ChangeListener<Number>() {
|
timeSlider.valueProperty().addListener(new ChangeListener<Number>() {
|
||||||
@Override
|
@Override
|
||||||
public void changed(ObservableValue<? extends Number> ov, Number old_val, Number new_val) {
|
public void changed(ObservableValue<? extends Number> ov, Number old_val, Number new_val) {
|
||||||
seekTime = (double) new_val * 1000 * 60;
|
seekTime = (long) ((double) new_val * 1000 * 60);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void stopBtnAction(ActionEvent event) {
|
void stopBtnAction(ActionEvent event) {
|
||||||
DBController.getInstance().setCurrentTime(film.getStreamUrl(), currentTime);
|
stop2();
|
||||||
mediaPlayer.stop();
|
|
||||||
player.getStage().close();
|
player.getStage().close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,11 +318,11 @@ public class PlayerController {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void playBtnAction(ActionEvent event) {
|
void playBtnAction(ActionEvent event) {
|
||||||
if (mediaPlayer.getStatus().equals(Status.PLAYING)) {
|
if (embeddedMediaPlayer.status().isPlaying()) {
|
||||||
mediaPlayer.pause();
|
embeddedMediaPlayer.controls().pause();
|
||||||
playIcon.setImage(playArrow);
|
playIcon.setImage(playArrow);
|
||||||
} else {
|
} else {
|
||||||
mediaPlayer.play();
|
embeddedMediaPlayer.controls().play();
|
||||||
playIcon.setImage(pause);
|
playIcon.setImage(pause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,7 +337,7 @@ public class PlayerController {
|
||||||
DBController.getInstance().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time
|
DBController.getInstance().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time
|
||||||
FilmTabelDataType nextFilm = DBController.getInstance().getNextEpisode(film.getTitle(), episode, season);
|
FilmTabelDataType nextFilm = DBController.getInstance().getNextEpisode(film.getTitle(), episode, season);
|
||||||
if (nextFilm != null) {
|
if (nextFilm != null) {
|
||||||
mediaPlayer.stop();
|
mediaPlayer2.stop();
|
||||||
film = nextFilm;
|
film = nextFilm;
|
||||||
init();
|
init();
|
||||||
autoplay = true;
|
autoplay = true;
|
||||||
|
@ -300,11 +345,52 @@ public class PlayerController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaPlayer getMediaPlayer() {
|
public MediaPlayer getMediaPlayer() {
|
||||||
return mediaPlayer;
|
return mediaPlayer2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getCurrentTime() {
|
public double getCurrentTime() {
|
||||||
return currentTime;
|
return currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, ByteBuffer[] nativeBuffers,
|
||||||
|
BufferFormat bufferFormat) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
videoPixelBuffer.updateBuffer(pb -> null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<HBox alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<HBox alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
<children>
|
<children>
|
||||||
<MediaView fx:id="mediaView" />
|
<MediaView fx:id="mediaView" />
|
||||||
|
<ImageView fx:id="videoImageView" pickOnBounds="true" preserveRatio="true" />
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
<VBox fx:id="bottomVBox" alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
|
<VBox fx:id="bottomVBox" alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
|
||||||
|
@ -39,7 +40,7 @@
|
||||||
<graphic>
|
<graphic>
|
||||||
<ImageView fx:id="playIcon" fitHeight="29.0" pickOnBounds="true" preserveRatio="true">
|
<ImageView fx:id="playIcon" fitHeight="29.0" pickOnBounds="true" preserveRatio="true">
|
||||||
<image>
|
<image>
|
||||||
<Image url="@../icons/baseline_play_arrow_black_48dp.png" />
|
<Image url="@../icons/baseline_pause_black_48dp.png" />
|
||||||
</image>
|
</image>
|
||||||
</ImageView>
|
</ImageView>
|
||||||
</graphic></JFXButton>
|
</graphic></JFXButton>
|
||||||
|
|
Loading…
Reference in New Issue