diff --git a/.gitignore b/.gitignore
index 7568db7..d1c36b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,4 +45,7 @@ dependency-reduced-pom.xml
.idea
## This is for our app, cause it likes to store stuff ##
-network_cameras.json
\ No newline at end of file
+network_cameras.json
+
+## exec launch4j config ##
+execfg.xml
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5e4fbc7..4bccba9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
io.swtc
swtc
1.0-SNAPSHOT
-
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.6.1
+
+
+ package
+
+ shade
+
+
+
+
+
+ io.swtc.Main
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
17
@@ -63,30 +100,30 @@
0.3.12
-
-
- org.lwjgl
- lwjgl
- 3.3.3
-
-
- org.lwjgl
- lwjgl-opengl
- 3.3.3
-
+
+
+
+
+
+
+
+
+
+
+
-
- org.lwjgl
- lwjgl
- 3.3.3
- natives-windows
-
-
- org.lwjgl
- lwjgl-opengl
- 3.3.3
- natives-windows
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -106,22 +143,35 @@
2.20.1
-
-
-
- org.jcodec
- jcodec
- 0.2.5
-
+
+
+
+
+
+
+
+
+
-
-
- org.jcodec
- jcodec-javase
- 0.2.5
-
+
+
+
+
+
+
+
+
+ org.bytedeco
+ javacv
+ 1.5.10
+
+
+
+ org.bytedeco
+ ffmpeg
+ 6.1.1-1.5.10
+ windows-x86_64
+
\ No newline at end of file
diff --git a/readme.md b/readme.md
index b8e459f..19d6bf7 100644
--- a/readme.md
+++ b/readme.md
@@ -1,26 +1,47 @@
-# SWT-CCTV
+# SWT-CCTV (Simple Watch Tool)
A rather simple CCTV software which operates with Java.
If you want to build this project on yourself, you will need IntelliJ (or any other IDE) and Maven!
+If you are looking for a desktop like experience this is the software, it has its own windowing system!
+
+## Downloads:
+
+If you are looking for downloads then you are in luck! Currently there are Windows Executables and portable Jar Files in place!
+Take a look at the [releases](https://rattatwinko.servecounterstrike.com/gitea/rattatwinko/swt-cctv/releases) page for the newest software releases!
+
+[Releases Page](https://rattatwinko.servecounterstrike.com/gitea/rattatwinko/swt-cctv/releases)
## Dependencies:
- Webcam by Sarxos
- Swing (AWT)
-- _lwjgl (with opengl)_ → This is important for our goals of rendering on the GPU.
- junit for testing stuff
-- jcodec, in the future we will be recording using this
- Jackson (fasterxml) → serializing the config for network cams
+- JavaCV
+ - FFmpeg
### Future Plans:
-They arent too big, i want one thing more and that is some more utilities in the camera window.
+Implement some more JavaCV cause of performance.
-Protable Jar which can be run with JRE 17 (already done but not too good!)
+## Requirements:
+
+- JRE/JDK 1.8.00 - 25 ([Reccomended](https://adoptium.net/de/download?link=https%3A%2F%2Fgithub.com%2Fadoptium%2Ftemurin17-binaries%2Freleases%2Fdownload%2Fjdk-17.0.17%252B10%2FOpenJDK17U-jre_x64_windows_hotspot_17.0.17_10.msi&vendor=Adoptium))
+
+| System Requirements | Minimum Requirements | Reccomended Requirements |
+|--------------------- |---------------------------------------------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| **_CPU_** | [Intel(R) Celeron(R) CPU G550 @ 2.60GHz](https://www.techpowerup.com/cpu-specs/celeron-g550.c1339) **_Or any Dual Core CPU_** | [Intel® Core™ i5-3470](https://www.intel.de/content/www/de/de/products/sku/68316/intel-core-i53470-processor-6m-cache-up-to-3-60-ghz/specifications.html) Or any **_Quad (or more) Core CPU_** |
+| **_RAM_** | **2GB DDR3** | **4/8GB DDR3/4/5** (You can have **_more_** than this, _Java likes it_) |
+| **_JRE_** | Java Runtime Enviroment: [1.8.000](https://javadl.oracle.com/webapps/download/AutoDL?BundleId=252905_0d06828d282343ea81775b28020a7cd3) | Java Runtime Enviroment _(or JDK)_: [17](https://adoptium.net/download?link=https%3A%2F%2Fgithub.com%2Fadoptium%2Ftemurin17-binaries%2Freleases%2Fdownload%2Fjdk-17.0.17%252B10%2FOpenJDK17U-jre_x64_windows_hotspot_17.0.17_10.msi&vendor=Adoptium) |
+| **_Disk Space_** | **_100Mb of HDD/SSD_** Space for the Program (currently **40.3Mb**) ; _For Recording more is needed_ | _100Mb SSD Space_ ; For Recording more than 100Mb , this depends on how many cameras you have |
+
+**Note: This was tested on these CPU'S!**
### Future Plans:
- [x] basic network cam interfacing
-- [ ] better multiplexer (or whatever the viewport is called in cctv)
+- [x] better multiplexer (or whatever the viewport is called in cctv)
- [x] Protable .jar which can be run with **JRE 17**
+- [ / ] Performance stabilisation (currently it is in place, and this app can be run on shitty hardware, but it can be better (current low is a celeron g550))
+- [ ] JavaCV integration for cameras
### Author(s):
diff --git a/src/main/java/io/swtc/Main.java b/src/main/java/io/swtc/Main.java
index 1f9211f..4eb4f76 100644
--- a/src/main/java/io/swtc/Main.java
+++ b/src/main/java/io/swtc/Main.java
@@ -2,20 +2,12 @@ package io.swtc;
import javax.swing.*;
-import io.swtc.proccessing.ui.ShowError;
-
public class Main {
public static void main(String[] args) {
- for (int i = 0; i < args.length; i++) {
- System.out.println("Arg " + i + ": " + args[i]);
- }
-
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- } catch (Exception e) {
- ShowError.warning(null,"LaF Warn","LaF");
- }
+ } catch (Exception e) { /* Do nothing */ }
SwingCCTVManager.main(null);
}
diff --git a/src/main/java/io/swtc/SwingCCTVManager.java b/src/main/java/io/swtc/SwingCCTVManager.java
index 89cd90a..9327aa5 100644
--- a/src/main/java/io/swtc/SwingCCTVManager.java
+++ b/src/main/java/io/swtc/SwingCCTVManager.java
@@ -2,25 +2,37 @@ package io.swtc;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamCompositeDriver;
+import com.github.sarxos.webcam.WebcamDevice;
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
-import com.github.sarxos.webcam.ds.ipcam.IpCamDeviceRegistry;
-import com.github.sarxos.webcam.ds.ipcam.IpCamDriver;
-import com.github.sarxos.webcam.ds.ipcam.IpCamMode;
+import com.github.sarxos.webcam.ds.ipcam.*;
import io.swtc.networking.CameraConfig;
import io.swtc.networking.CameraSettings;
+import io.swtc.proccessing.ui.IconSetter;
+import io.swtc.proccessing.ui.ShowError;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.io.File;
+import java.net.InetSocketAddress;
import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URL;
import java.util.List;
public class SwingCCTVManager {
+ private static final String TIMEOUT_MS = "1500";
+ private static final int REFRESH_INTERVAL = 30000;
+ private static final String STATUS_ONLINE = "ONLINE";
+ private static final String STATUS_OFFLINE = "OFFLINE";
+
static {
+ System.setProperty("ipcam.connection.timeout", TIMEOUT_MS);
Webcam.setDriver(new WebcamCompositeDriver() {{
add(new WebcamDefaultDriver());
add(new IpCamDriver());
@@ -32,206 +44,237 @@ public class SwingCCTVManager {
private final JTable deviceTable;
private final DefaultTableModel tableModel;
private final SwingIFrame IFrame;
-
+ private boolean isRefreshing = false;
public SwingCCTVManager() {
- frame = new JFrame("dashboard");
+ frame = new JFrame("Dashboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setSize(1000, 600);
+ frame.setSize(1100, 600);
+ frame.setIconImage(IconSetter.getIcon());
this.IFrame = new SwingIFrame();
this.IFrame.show();
- String[] columns = {"Status", "Device Name", "Type", "Resolution", "Address"};
- tableModel = new DefaultTableModel(columns, 0) {
+ tableModel = new DefaultTableModel(new String[]{"Status", "Device Name", "Type", "Resolution", "Address"}, 0) {
@Override
- public boolean isCellEditable(int r, int c) {
- return false;
- }
+ public boolean isCellEditable(int r, int c) { return false; }
};
deviceTable = new JTable(tableModel);
-
- deviceTable.setRowSelectionAllowed(true);
- deviceTable.setFocusable(true);
- deviceTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-
setupTableAppearance();
-
- deviceTable.addMouseListener(new MouseAdapter() {
- @Override
- public void mousePressed(MouseEvent e) {
- deviceTable.requestFocusInWindow();
-
- if (e.getClickCount() == 2 && deviceTable.getSelectedRow() != -1) {
- launchSelected();
- }
- if (SwingUtilities.isRightMouseButton(e)) {
- showContextMenu(e);
- }
- }
- });
+ setupDragAndDrop(); // Initialize DND
+ setupListeners();
JToolBar toolBar = new JToolBar();
- JButton btnAdd = new JButton("Add IP Cam");
- JButton btnLaunch = new JButton("Launch Stream");
- toolBar.add(btnAdd);
- toolBar.addSeparator();
- toolBar.add(btnLaunch);
+ setupBrandedToolbar(toolBar);
- frame.add(toolBar, BorderLayout.NORTH);
+ frame.add(toolBar, BorderLayout.SOUTH);
frame.add(new JScrollPane(deviceTable), BorderLayout.CENTER);
- btnAdd.addActionListener(e -> showAddCameraDialog());
- btnLaunch.addActionListener(e -> launchSelected());
-
startAutoRefresh();
refreshTable();
}
- private void setupTableAppearance() {
- deviceTable.getColumnModel().getColumn(0).setMaxWidth(80);
- deviceTable.setRowHeight(30);
-
- deviceTable.getColumnModel().getColumn(0)
- .setCellRenderer(new DefaultTableCellRenderer() {
- @Override
- public Component getTableCellRendererComponent(
- JTable t, Object v, boolean s, boolean f, int r, int c) {
-
- Component comp = super.getTableCellRendererComponent(t, v, s, f, r, c);
- setHorizontalAlignment(JLabel.CENTER);
- comp.setForeground("ONLINE".equals(v)
- ? new Color(0, 150, 0)
- : Color.RED);
- return comp;
- }
- });
- }
-
- private void startAutoRefresh() {
- new Timer(5000, e -> refreshTable()).start();
- }
-
- private void refreshTable() {
- int[] selectedRows = deviceTable.getSelectedRows();
-
- tableModel.setRowCount(0);
- List webcams = Webcam.getWebcams();
-
- for (Webcam w : webcams) {
- boolean isIp = w.getDevice().getClass().getSimpleName().contains("IpCam");
- String status = w.getDevice() != null ? "ONLINE" : "OFFLINE";
-
- tableModel.addRow(new Object[]{
- status,
- w.getName(),
- isIp ? "IP Stream" : "USB Hardware",
- w.getViewSize().width + "x" + w.getViewSize().height,
- isIp ? "Network" : "Local"
- });
+ private void setupBrandedToolbar(JToolBar toolBar) {
+ Image ogIcon = IconSetter.getIcon();
+ if (ogIcon != null) {
+ Image scaledIcon = ogIcon.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
+ toolBar.add(new JLabel(new ImageIcon(scaledIcon)));
}
- for (int r : selectedRows) {
- if (r < tableModel.getRowCount()) {
- deviceTable.addRowSelectionInterval(r, r);
+ toolBar.add(new JLabel("SWT-CCTV"));
+ toolBar.add(Box.createRigidArea(new Dimension(10, 0)));
+ toolBar.addSeparator(new Dimension(10, 32));
+
+ JButton btnAdd = new JButton("Add IP Cam");
+ JButton btnImport = new JButton("Import Config"); // New Import Button
+ JButton btnLaunch = new JButton("Launch Stream");
+
+ btnAdd.setPreferredSize(new Dimension(100, 32));
+ btnImport.setPreferredSize(new Dimension(110, 32));
+ btnLaunch.setPreferredSize(new Dimension(120, 32));
+
+ toolBar.add(Box.createRigidArea(new Dimension(5, 0)));
+ toolBar.add(btnAdd);
+ toolBar.add(btnImport);
+ toolBar.addSeparator();
+ toolBar.add(btnLaunch);
+
+ btnAdd.addActionListener(e -> showAddCameraDialog());
+ btnImport.addActionListener(e -> showImportDialog());
+ btnLaunch.addActionListener(e -> launchSelected());
+ }
+
+ private void setupDragAndDrop() {
+ deviceTable.setDragEnabled(true);
+ deviceTable.setTransferHandler(new TransferHandler() {
+ @Override
+ public boolean canImport(TransferSupport support) {
+ return support.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
}
+
+ @Override
+ public boolean importData(TransferSupport support) {
+ if (!canImport(support)) return false;
+ try {
+ @SuppressWarnings("unchecked")
+ List files = (List) support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
+ for (File file : files) {
+ if (file.getName().endsWith(".json")) {
+ List configs = CameraSettings.loadFromFile(file);
+ importCameras(configs);
+ }
+ }
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ });
+ }
+
+ private void showImportDialog() {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setDialogTitle("Select Camera Configuration JSON");
+ if (chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION) {
+ File file = chooser.getSelectedFile();
+ List configs = CameraSettings.loadFromFile(file);
+ importCameras(configs);
}
}
- private void showContextMenu(MouseEvent e) {
- int row = deviceTable.rowAtPoint(e.getPoint());
- if (row >= 0) {
- deviceTable.setRowSelectionInterval(row, row);
+ private void importCameras(List configs) {
+ if (configs.isEmpty()) {
+ ShowError.warning(frame, "Import Empty", "No valid camera configurations found in file.");
+ return;
}
+ for (CameraConfig config : configs) {
+ try {
+ if (!IpCamDeviceRegistry.isRegistered(config.getName())) {
+ IpCamDeviceRegistry.register(config.getName(), config.getUrl(), IpCamMode.PUSH);
+ CameraSettings.save(config);
+ }
+ } catch (Exception ignored) {}
+ }
+ refreshTable();
+ }
- JPopupMenu menu = new JPopupMenu();
- JMenuItem launch = new JMenuItem("Launch Live Stream");
- JMenuItem delete = new JMenuItem("Remove Device");
+ private void setupTableAppearance() {
+ deviceTable.setRowHeight(30);
+ deviceTable.getColumnModel().getColumn(0).setMaxWidth(80);
+ deviceTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
+ @Override
+ public Component getTableCellRendererComponent(JTable t, Object v, boolean s, boolean f, int r, int c) {
+ Component comp = super.getTableCellRendererComponent(t, v, s, f, r, c);
+ setHorizontalAlignment(JLabel.CENTER);
+ comp.setForeground(STATUS_ONLINE.equals(v) ? new Color(0, 150, 0) : Color.RED);
+ return comp;
+ }
+ });
+ }
- launch.addActionListener(al -> launchSelected());
- delete.addActionListener(al -> deleteSelected());
+ private synchronized void refreshTable() {
+ if (isRefreshing) return;
+ isRefreshing = true;
+ final int selectedRow = deviceTable.getSelectedRow();
+ new SwingWorker() {
+ @Override
+ protected Void doInBackground() {
+ for (WebcamDevice device : new WebcamDefaultDriver().getDevices()) {
+ Dimension res = (device.getResolutions().length > 0) ? device.getResolutions()[0] : new Dimension(0,0);
+ publish(new Object[]{STATUS_ONLINE, device.getName(), "USB Hardware", res.width + "x" + res.height, "Local"});
+ }
+ for (IpCamDevice ipDevice : IpCamDeviceRegistry.getIpCameras()) {
+ publish(probeIpCamera(ipDevice));
+ }
+ return null;
+ }
+ @Override
+ protected void process(List