forked from j62/ctbrec
Tweak video preview in thumb cell
This commit is contained in:
parent
d09aad1bf6
commit
f631306768
|
@ -22,6 +22,7 @@ import ctbrec.Model;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.ui.action.PlayAction;
|
import ctbrec.ui.action.PlayAction;
|
||||||
|
import ctbrec.ui.controls.StreamPreview;
|
||||||
import javafx.animation.FadeTransition;
|
import javafx.animation.FadeTransition;
|
||||||
import javafx.animation.FillTransition;
|
import javafx.animation.FillTransition;
|
||||||
import javafx.animation.ParallelTransition;
|
import javafx.animation.ParallelTransition;
|
||||||
|
@ -43,6 +44,7 @@ import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.scene.shape.Shape;
|
import javafx.scene.shape.Shape;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
|
@ -58,6 +60,7 @@ public class ThumbCell extends StackPane {
|
||||||
private static final Duration ANIMATION_DURATION = new Duration(250);
|
private static final Duration ANIMATION_DURATION = new Duration(250);
|
||||||
|
|
||||||
private Model model;
|
private Model model;
|
||||||
|
private StreamPreview streamPreview;
|
||||||
private ImageView iv;
|
private ImageView iv;
|
||||||
private Rectangle resolutionBackground;
|
private Rectangle resolutionBackground;
|
||||||
private final Paint resolutionOnlineColor = new Color(0.22, 0.8, 0.29, 1);
|
private final Paint resolutionOnlineColor = new Color(0.22, 0.8, 0.29, 1);
|
||||||
|
@ -87,8 +90,10 @@ public class ThumbCell extends StackPane {
|
||||||
.expireAfterAccess(4, TimeUnit.HOURS)
|
.expireAfterAccess(4, TimeUnit.HOURS)
|
||||||
.maximumSize(1000)
|
.maximumSize(1000)
|
||||||
.build();
|
.build();
|
||||||
|
private ThumbOverviewTab parent;
|
||||||
|
|
||||||
public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder) {
|
public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder) {
|
||||||
|
this.parent = parent;
|
||||||
this.thumbCellList = parent.grid.getChildren();
|
this.thumbCellList = parent.grid.getChildren();
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
|
@ -96,6 +101,11 @@ public class ThumbCell extends StackPane {
|
||||||
model.setSuspended(recorder.isSuspended(model));
|
model.setSuspended(recorder.isSuspended(model));
|
||||||
this.setStyle("-fx-background-color: -fx-base");
|
this.setStyle("-fx-background-color: -fx-base");
|
||||||
|
|
||||||
|
streamPreview = new StreamPreview();
|
||||||
|
streamPreview.prefWidthProperty().bind(widthProperty());
|
||||||
|
streamPreview.prefHeightProperty().bind(heightProperty());
|
||||||
|
getChildren().add(streamPreview);
|
||||||
|
|
||||||
iv = new ImageView();
|
iv = new ImageView();
|
||||||
iv.setSmooth(true);
|
iv.setSmooth(true);
|
||||||
iv.setPreserveRatio(true);
|
iv.setPreserveRatio(true);
|
||||||
|
@ -164,8 +174,10 @@ public class ThumbCell extends StackPane {
|
||||||
StackPane.setAlignment(pausedIndicator, Pos.TOP_LEFT);
|
StackPane.setAlignment(pausedIndicator, Pos.TOP_LEFT);
|
||||||
getChildren().add(pausedIndicator);
|
getChildren().add(pausedIndicator);
|
||||||
|
|
||||||
|
getChildren().add(createPreviewTrigger());
|
||||||
|
|
||||||
selectionOverlay = new Rectangle();
|
selectionOverlay = new Rectangle();
|
||||||
selectionOverlay.setOpacity(0);
|
selectionOverlay.visibleProperty().bind(selectionProperty);
|
||||||
selectionOverlay.widthProperty().bind(widthProperty());
|
selectionOverlay.widthProperty().bind(widthProperty());
|
||||||
selectionOverlay.heightProperty().bind(heightProperty());
|
selectionOverlay.heightProperty().bind(heightProperty());
|
||||||
StackPane.setAlignment(selectionOverlay, Pos.TOP_LEFT);
|
StackPane.setAlignment(selectionOverlay, Pos.TOP_LEFT);
|
||||||
|
@ -197,6 +209,50 @@ public class ThumbCell extends StackPane {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node createPreviewTrigger() {
|
||||||
|
int s = 32;
|
||||||
|
StackPane previewTrigger = new StackPane();
|
||||||
|
previewTrigger.setStyle("-fx-background-color: white;");
|
||||||
|
previewTrigger.setOpacity(.8);
|
||||||
|
previewTrigger.setMaxSize(s, s);
|
||||||
|
|
||||||
|
Polygon play = new Polygon(new double[] {
|
||||||
|
16, 8,
|
||||||
|
26, 15,
|
||||||
|
16, 22
|
||||||
|
});
|
||||||
|
StackPane.setMargin(play, new Insets(0, 0, 0, 3));
|
||||||
|
play.setStyle("-fx-background-color: black;");
|
||||||
|
previewTrigger.getChildren().add(play);
|
||||||
|
|
||||||
|
Circle clip = new Circle(s / 2);
|
||||||
|
clip.setTranslateX(clip.getRadius());
|
||||||
|
clip.setTranslateY(clip.getRadius());
|
||||||
|
previewTrigger.setClip(clip);
|
||||||
|
StackPane.setAlignment(previewTrigger, Pos.BOTTOM_LEFT);
|
||||||
|
StackPane.setMargin(previewTrigger, new Insets(0, 0, 24, 4));
|
||||||
|
previewTrigger.setOnMouseEntered(evt -> setPreviewVisible(previewTrigger, true));
|
||||||
|
previewTrigger.setOnMouseExited(evt -> setPreviewVisible(previewTrigger, false));
|
||||||
|
return previewTrigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPreviewVisible(Node previewTrigger, boolean visible) {
|
||||||
|
parent.suspendUpdates(visible);
|
||||||
|
iv.setVisible(!visible);
|
||||||
|
topic.setVisible(!visible);
|
||||||
|
topicBackground.setVisible(!visible);
|
||||||
|
name.setVisible(!visible);
|
||||||
|
nameBackground.setVisible(!visible);
|
||||||
|
streamPreview.setVisible(visible);
|
||||||
|
streamPreview.startStream(model);
|
||||||
|
recordingIndicator.setVisible(!visible);
|
||||||
|
pausedIndicator.setVisible(!visible);
|
||||||
|
if(!visible) {
|
||||||
|
updateRecordingIndicator();
|
||||||
|
}
|
||||||
|
previewTrigger.setCursor(visible ? Cursor.HAND : Cursor.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSelected(boolean selected) {
|
public void setSelected(boolean selected) {
|
||||||
selectionProperty.set(selected);
|
selectionProperty.set(selected);
|
||||||
selectionOverlay.getStyleClass().add("selection-background");
|
selectionOverlay.getStyleClass().add("selection-background");
|
||||||
|
@ -356,6 +412,10 @@ public class ThumbCell extends StackPane {
|
||||||
nameBackground.setFill(c);
|
nameBackground.setFill(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateRecordingIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRecordingIndicator() {
|
||||||
if(recording) {
|
if(recording) {
|
||||||
recordingIndicator.setVisible(!model.isSuspended());
|
recordingIndicator.setVisible(!model.isSuspended());
|
||||||
pausedIndicator.setVisible(model.isSuspended());
|
pausedIndicator.setVisible(model.isSuspended());
|
||||||
|
@ -574,13 +634,15 @@ public class ThumbCell extends StackPane {
|
||||||
nameBackground.setWidth(w);
|
nameBackground.setWidth(w);
|
||||||
nameBackground.setHeight(20);
|
nameBackground.setHeight(20);
|
||||||
topicBackground.setWidth(w);
|
topicBackground.setWidth(w);
|
||||||
topicBackground.setHeight(getHeight()-nameBackground.getHeight());
|
topicBackground.setHeight(h - nameBackground.getHeight());
|
||||||
topic.prefHeight(getHeight()-25);
|
topic.prefHeight(getHeight()-25);
|
||||||
topic.maxHeight(getHeight()-25);
|
topic.maxHeight(getHeight()-25);
|
||||||
int margin = 4;
|
int margin = 4;
|
||||||
topic.maxWidth(w-margin*2);
|
topic.maxWidth(w-margin*2);
|
||||||
topic.setWrappingWidth(w-margin*2);
|
topic.setWrappingWidth(w-margin*2);
|
||||||
|
|
||||||
|
streamPreview.resizeTo(w, h);
|
||||||
|
|
||||||
Rectangle clip = new Rectangle(w, h);
|
Rectangle clip = new Rectangle(w, h);
|
||||||
clip.setArcWidth(10);
|
clip.setArcWidth(10);
|
||||||
clip.arcHeightProperty().bind(clip.arcWidthProperty());
|
clip.arcHeightProperty().bind(clip.arcWidthProperty());
|
||||||
|
|
|
@ -34,8 +34,8 @@ public class StreamPreview extends StackPane {
|
||||||
private MediaPlayer videoPlayer;
|
private MediaPlayer videoPlayer;
|
||||||
private Media video;
|
private Media video;
|
||||||
private ProgressIndicator progressIndicator;
|
private ProgressIndicator progressIndicator;
|
||||||
private ExecutorService executor = Executors.newSingleThreadExecutor();
|
private static ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
private Future<?> future;
|
private static Future<?> future;
|
||||||
|
|
||||||
public StreamPreview() {
|
public StreamPreview() {
|
||||||
videoPreview = new MediaView();
|
videoPreview = new MediaView();
|
||||||
|
@ -53,7 +53,6 @@ public class StreamPreview extends StackPane {
|
||||||
|
|
||||||
progressIndicator = new ProgressIndicator();
|
progressIndicator = new ProgressIndicator();
|
||||||
progressIndicator.setVisible(false);
|
progressIndicator.setVisible(false);
|
||||||
progressIndicator.prefWidthProperty().bind(videoPreview.fitWidthProperty());
|
|
||||||
|
|
||||||
Region veil = new Region();
|
Region veil = new Region();
|
||||||
veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.8)");
|
veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.8)");
|
||||||
|
@ -64,14 +63,25 @@ public class StreamPreview extends StackPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startStream(Model model) {
|
public void startStream(Model model) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
progressIndicator.setVisible(true);
|
||||||
|
if(model.getPreview() != null) {
|
||||||
|
try {
|
||||||
|
videoPreview.setVisible(false);
|
||||||
|
Image img = new Image(model.getPreview(), true);
|
||||||
|
preview.setImage(img);
|
||||||
|
double aspect = img.getWidth() / img.getHeight();
|
||||||
|
double w = Config.getInstance().getSettings().thumbWidth;
|
||||||
|
double h = w / aspect;
|
||||||
|
resizeTo(w, h);
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
if(future != null && !future.isDone()) {
|
if(future != null && !future.isDone()) {
|
||||||
future.cancel(true);
|
future.cancel(true);
|
||||||
}
|
}
|
||||||
future = executor.submit(() -> {
|
future = executor.submit(() -> {
|
||||||
try {
|
try {
|
||||||
Platform.runLater(() -> {
|
|
||||||
progressIndicator.setVisible(true);
|
|
||||||
});
|
|
||||||
List<StreamSource> sources = model.getStreamSources();
|
List<StreamSource> sources = model.getStreamSources();
|
||||||
Collections.sort(sources);
|
Collections.sort(sources);
|
||||||
StreamSource best = sources.get(0);
|
StreamSource best = sources.get(0);
|
||||||
|
@ -90,7 +100,7 @@ public class StreamPreview extends StackPane {
|
||||||
double aspect = (double)video.getWidth() / video.getHeight();
|
double aspect = (double)video.getWidth() / video.getHeight();
|
||||||
double w = Config.getInstance().getSettings().thumbWidth;
|
double w = Config.getInstance().getSettings().thumbWidth;
|
||||||
double h = w / aspect;
|
double h = w / aspect;
|
||||||
resizeToFitContent(w, h);
|
resizeTo(w, h);
|
||||||
progressIndicator.setVisible(false);
|
progressIndicator.setVisible(false);
|
||||||
videoPreview.setVisible(true);
|
videoPreview.setVisible(true);
|
||||||
videoPreview.setMediaPlayer(videoPlayer);
|
videoPreview.setMediaPlayer(videoPlayer);
|
||||||
|
@ -127,23 +137,23 @@ public class StreamPreview extends StackPane {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resizeToFitContent(double w, double h) {
|
public void resizeTo(double w, double h) {
|
||||||
setPrefSize(w, h);
|
|
||||||
preview.setFitWidth(w);
|
preview.setFitWidth(w);
|
||||||
preview.setFitHeight(h);
|
preview.setFitHeight(h);
|
||||||
videoPreview.setFitWidth(w);
|
videoPreview.setFitWidth(w);
|
||||||
videoPreview.setFitHeight(h);
|
videoPreview.setFitHeight(h);
|
||||||
|
progressIndicator.setPrefSize(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
if(future != null && !future.isDone()) {
|
if(future != null && !future.isDone()) {
|
||||||
future.cancel(true);
|
future.cancel(true);
|
||||||
}
|
}
|
||||||
Platform.runLater(() -> {
|
new Thread(() -> {
|
||||||
if(videoPlayer != null) {
|
if(videoPlayer != null) {
|
||||||
videoPlayer.dispose();
|
videoPlayer.dispose();
|
||||||
}
|
}
|
||||||
});
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onError(MediaPlayer videoPlayer) {
|
private void onError(MediaPlayer videoPlayer) {
|
||||||
|
@ -151,7 +161,7 @@ public class StreamPreview extends StackPane {
|
||||||
if(videoPlayer.getError().getCause() != null) {
|
if(videoPlayer.getError().getCause() != null) {
|
||||||
LOG.error("Error while starting preview stream root cause:", videoPlayer.getError().getCause());
|
LOG.error("Error while starting preview stream root cause:", videoPlayer.getError().getCause());
|
||||||
}
|
}
|
||||||
videoPlayer.dispose();
|
stop();
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
showTestImage();
|
showTestImage();
|
||||||
});
|
});
|
||||||
|
@ -165,7 +175,7 @@ public class StreamPreview extends StackPane {
|
||||||
double aspect = img.getWidth() / img.getHeight();
|
double aspect = img.getWidth() / img.getHeight();
|
||||||
double w = Config.getInstance().getSettings().thumbWidth;
|
double w = Config.getInstance().getSettings().thumbWidth;
|
||||||
double h = w / aspect;
|
double h = w / aspect;
|
||||||
resizeToFitContent(w, h);
|
resizeTo(w, h);
|
||||||
progressIndicator.setVisible(false);
|
progressIndicator.setVisible(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue