forked from j62/ctbrec
1
0
Fork 0

Add max resolution setting for the player

This commit is contained in:
0xboobface 2020-05-31 14:50:12 +02:00
parent 79892b1a13
commit b87f090ac3
7 changed files with 157 additions and 23 deletions

View File

@ -1,6 +1,7 @@
package ctbrec.ui; package ctbrec.ui;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@ -9,11 +10,18 @@ import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.xml.bind.JAXBException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.PlaylistException;
import ctbrec.Config; import ctbrec.Config;
import ctbrec.Hmac; import ctbrec.Hmac;
import ctbrec.Model; import ctbrec.Model;
@ -32,11 +40,7 @@ public class Player {
private Player() { private Player() {
} }
public static boolean play(String url) { private static boolean play(String url, boolean async) {
return play(url, true);
}
public static boolean play(String url, boolean async) {
boolean singlePlayer = Config.getInstance().getSettings().singlePlayer; boolean singlePlayer = Config.getInstance().getSettings().singlePlayer;
try { try {
if (singlePlayer && playerThread != null && playerThread.isRunning()) { if (singlePlayer && playerThread != null && playerThread.isRunning()) {
@ -80,11 +84,9 @@ public class Player {
if (singlePlayer && playerThread != null && playerThread.isRunning()) { if (singlePlayer && playerThread != null && playerThread.isRunning()) {
playerThread.stopThread(); playerThread.stopThread();
} }
List<StreamSource> sources = model.getStreamSources(); String playlistUrl = getPlaylistUrl(model);
Collections.sort(sources); LOG.debug("Playing {}", playlistUrl);
StreamSource best = sources.get(sources.size() - 1); return Player.play(playlistUrl, async);
LOG.debug("Playing {}", best.getMediaPlaylistUrl());
return Player.play(best.getMediaPlaylistUrl(), async);
} else { } else {
Dialogs.showError(scene, "Room not public", "Room is currently not public", null); Dialogs.showError(scene, "Room not public", "Room is currently not public", null);
return false; return false;
@ -96,6 +98,29 @@ public class Player {
} }
} }
private static String getPlaylistUrl(Model model) throws IOException, ExecutionException, ParseException, PlaylistException, JAXBException {
List<StreamSource> sources = model.getStreamSources();
Collections.sort(sources);
StreamSource best;
int maxRes = Config.getInstance().getSettings().maximumResolutionPlayer;
if (maxRes > 0 && !sources.isEmpty()) {
for (Iterator<StreamSource> iterator = sources.iterator(); iterator.hasNext();) {
StreamSource streamSource = iterator.next();
if (streamSource.height > 0 && maxRes < streamSource.height) {
LOG.trace("Res too high {} > {}", streamSource.height, maxRes);
iterator.remove();
}
}
}
if (sources.isEmpty()) {
throw new RuntimeException("No stream left in playlist, because player resolution is set to " + maxRes);
} else {
LOG.debug("{} selected {}", model.getName(), sources.get(sources.size() - 1));
best = sources.get(sources.size() - 1);
}
return best.getMediaPlaylistUrl();
}
public static void stop() { public static void stop() {
if (playerThread != null) { if (playerThread != null) {
playerThread.stopThread(); playerThread.stopThread();

View File

@ -0,0 +1,101 @@
package ctbrec.ui.settings;
import java.io.IOException;
import java.io.InputStream;
import ctbrec.Config;
import ctbrec.Settings;
import ctbrec.ui.controls.Dialogs;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class PlayerSettingsDialog extends Dialog<Exception> {
private Scene parent;
private Config config;
private Settings settings;
private TextField playerParams;
private TextField maxResolution;
public PlayerSettingsDialog(Scene parent, Config config) {
this.parent = parent;
this.config = config;
this.settings = config.getSettings();
initGui();
}
private void initGui() {
setTitle("Player Settings");
setHeaderText("Player Settings");
getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
initModality(Modality.APPLICATION_MODAL);
setResizable(true);
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
Stage stage = (Stage) getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image(icon));
if (parent != null) {
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
}
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 150, 10, 10));
grid.add(new Label("Start parameters"), 0, 0);
playerParams = new TextField(settings.mediaPlayerParams);
grid.add(playerParams, 1, 0);
getDialogPane().setContent(grid);
GridPane.setFillWidth(playerParams, true);
GridPane.setHgrow(playerParams, Priority.ALWAYS);
Label l = new Label("Maximum resolution (0 = unlimited)");
grid.add(l, 0, 1);
maxResolution = new TextField(Integer.toString(settings.maximumResolutionPlayer));
Tooltip tt = new Tooltip("video height, e.g. 720 or 1080");
l.setTooltip(tt);
maxResolution.setTooltip(tt);
grid.add(maxResolution, 1, 1);
getDialogPane().setContent(grid);
GridPane.setFillWidth(maxResolution, true);
GridPane.setHgrow(maxResolution, Priority.ALWAYS);
Platform.runLater(playerParams::requestFocus);
setResultConverter(dialogButton -> {
try {
if (dialogButton == ButtonType.OK) {
saveSettings();
}
return null;
} catch (IOException e) {
return e;
}
});
}
public void saveSettings() throws IOException {
settings.mediaPlayerParams = playerParams.getText();
String res = maxResolution.getText();
if (res.matches("\\d+")) {
int newRes = Integer.parseInt(maxResolution.getText());
if (newRes != Config.getInstance().getSettings().maximumResolutionPlayer) {
settings.maximumResolutionPlayer = newRes;
}
}
config.save();
}
}

View File

@ -67,7 +67,7 @@ import javafx.stage.FileChooser;
public class SettingsTab extends Tab implements TabSelectionListener { public class SettingsTab extends Tab implements TabSelectionListener {
private static final String PATTERN_NOT_A_DIGIT = "[^\\d]"; public static final String PATTERN_NOT_A_DIGIT = "[^\\d]";
private static final Logger LOG = LoggerFactory.getLogger(SettingsTab.class); private static final Logger LOG = LoggerFactory.getLogger(SettingsTab.class);
private static final int ONE_GIB_IN_BYTES = 1024 * 1024 * 1024; private static final int ONE_GIB_IN_BYTES = 1024 * 1024 * 1024;
@ -626,12 +626,17 @@ public class SettingsTab extends Tab implements TabSelectionListener {
layout.add(mediaPlayer, 1, row); layout.add(mediaPlayer, 1, row);
Button mediaPlayerParamsButton = new Button(""); Button mediaPlayerParamsButton = new Button("");
mediaPlayerParamsButton.setOnAction(e -> { mediaPlayerParamsButton.setOnAction(e -> {
Optional<String> playerParams = Dialogs.showTextInput(mediaPlayerParamsButton.getScene(), "Media Player Parameters", // Optional<String> playerParams = Dialogs.showTextInput(mediaPlayerParamsButton.getScene(), "Media Player Parameters",
"Media Player Start Parameters", settings.mediaPlayerParams); // "Media Player Start Parameters", settings.mediaPlayerParams);
playerParams.ifPresent(p -> { // playerParams.ifPresent(p -> {
settings.mediaPlayerParams = p; // settings.mediaPlayerParams = p;
saveConfig(); // saveConfig();
}); // });
PlayerSettingsDialog dialog = new PlayerSettingsDialog(getTabPane().getScene(), Config.getInstance());
Optional<Exception> exception = dialog.showAndWait();
if (exception.isPresent()) {
Dialogs.showError("Saving player parameters", "Player parameters couldn't be saved", exception.get());
}
}); });
layout.add(mediaPlayerParamsButton, 3, row++); layout.add(mediaPlayerParamsButton, 3, row++);

View File

@ -70,6 +70,7 @@ public class Settings {
public boolean livePreviews = false; public boolean livePreviews = false;
public boolean localRecording = true; public boolean localRecording = true;
public int maximumResolution = 0; public int maximumResolution = 0;
public int maximumResolutionPlayer = 0;
public String mediaPlayer = "/usr/bin/mpv"; public String mediaPlayer = "/usr/bin/mpv";
public String mediaPlayerParams = ""; public String mediaPlayerParams = "";
public String mfcBaseUrl = "https://www.myfreecams.com"; public String mfcBaseUrl = "https://www.myfreecams.com";

View File

@ -5,6 +5,7 @@ import static ctbrec.io.HttpConstants.*;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -44,7 +45,7 @@ public class CamsodaModel extends AbstractModel {
private static final String STATUS = "status"; private static final String STATUS = "status";
private static final Logger LOG = LoggerFactory.getLogger(CamsodaModel.class); private static final Logger LOG = LoggerFactory.getLogger(CamsodaModel.class);
private String streamUrl; private String streamUrl;
private List<StreamSource> streamSources = null; private transient List<StreamSource> streamSources = null;
private float sortOrder = 0; private float sortOrder = 0;
private Random random = new Random(); private Random random = new Random();
int[] resolution = new int[2]; int[] resolution = new int[2];
@ -126,7 +127,8 @@ public class CamsodaModel extends AbstractModel {
streamsource.width = 0; streamsource.width = 0;
streamsource.height = 0; streamsource.height = 0;
} }
streamSources = Collections.singletonList(streamsource); streamSources = new ArrayList<>();
streamSources.add(streamsource);
} else { } else {
LOG.trace("Response: {}", response.body().string()); LOG.trace("Response: {}", response.body().string());
throw new HttpException(response.code(), response.message()); throw new HttpException(response.code(), response.message());

View File

@ -104,8 +104,6 @@ public class ShowupHttpClient extends HttpClient {
JSONObject json = new JSONObject(responseBody); JSONObject json = new JSONObject(responseBody);
return json.optString("status").equalsIgnoreCase("success"); return json.optString("status").equalsIgnoreCase("success");
} else { } else {
String msg = "Login was not successful";
LOG.warn("{}\n{}", msg, responseBody);
return false; return false;
} }
} else { } else {

View File

@ -4,7 +4,7 @@ import static ctbrec.Model.State.*;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -70,7 +70,9 @@ public class ShowupModel extends AbstractModel {
int cdnHost = 1 + new Random().nextInt(5); int cdnHost = 1 + new Random().nextInt(5);
src.mediaPlaylistUrl = MessageFormat.format("https://cdn-e0{0}.showup.tv/h5live/http/playlist.m3u8?url=rtmp%3A%2F%2F{1}%3A1935%2Fwebrtc&stream={2}_aac", cdnHost, streamTranscoderAddr, streamId); src.mediaPlaylistUrl = MessageFormat.format("https://cdn-e0{0}.showup.tv/h5live/http/playlist.m3u8?url=rtmp%3A%2F%2F{1}%3A1935%2Fwebrtc&stream={2}_aac", cdnHost, streamTranscoderAddr, streamId);
return Collections.singletonList(src); List<StreamSource> sources = new ArrayList<>();
sources.add(src);
return sources;
} }
@Override @Override