stabilisation #2

Merged
rattatwinko merged 10 commits from stabilisation into main 2026-02-19 14:14:22 +00:00
7 changed files with 240 additions and 19 deletions
Showing only changes of commit e225d8f0bc - Show all commits

View File

@@ -1,26 +1,47 @@
# SWT-CCTV # SWT-CCTV (Simple Watch Tool)
A rather simple CCTV software which operates with Java. 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 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: ## Dependencies:
- Webcam by Sarxos - Webcam by Sarxos
- Swing (AWT) - Swing (AWT)
- _lwjgl (with opengl)_ → This is important for our goals of rendering on the GPU.
- junit for testing stuff - junit for testing stuff
- jcodec, in the future we will be recording using this
- Jackson (fasterxml) → serializing the config for network cams - Jackson (fasterxml) → serializing the config for network cams
- JavaCV
- FFmpeg
### Future Plans: ### 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: ### Future Plans:
- [x] basic network cam interfacing - [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** - [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): ### Author(s):

View File

@@ -2,16 +2,9 @@ package io.swtc;
import javax.swing.*; import javax.swing.*;
import io.swtc.proccessing.ui.IconSetter;
import io.swtc.proccessing.ui.ShowError;
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
// for (int i = 0; i < args.length; i++) {
// System.out.println("Arg " + i + ": " + args[i]);
// }
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) { /* Do nothing */ } } catch (Exception e) { /* Do nothing */ }

View File

@@ -45,7 +45,6 @@ public class SwingCCTVManager {
private final DefaultTableModel tableModel; private final DefaultTableModel tableModel;
private final SwingIFrame IFrame; private final SwingIFrame IFrame;
private boolean isRefreshing = false; private boolean isRefreshing = false;
public SwingCCTVManager() { public SwingCCTVManager() {
frame = new JFrame("Dashboard"); frame = new JFrame("Dashboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

View File

@@ -3,6 +3,7 @@ package io.swtc;
import com.github.sarxos.webcam.Webcam; import com.github.sarxos.webcam.Webcam;
import io.swtc.proccessing.ui.IconSetter; import io.swtc.proccessing.ui.IconSetter;
import io.swtc.proccessing.ui.desktop.DIM; import io.swtc.proccessing.ui.desktop.DIM;
import io.swtc.proccessing.ui.desktop.debug.Profiler;
import io.swtc.proccessing.ui.desktop.evidence.EvidenceExportFrame; import io.swtc.proccessing.ui.desktop.evidence.EvidenceExportFrame;
import io.swtc.proccessing.ui.iframe.*; import io.swtc.proccessing.ui.iframe.*;
import javax.swing.*; import javax.swing.*;
@@ -42,6 +43,7 @@ public class SwingIFrame {
desktopIconManager = new DIM(desktopPane); desktopIconManager = new DIM(desktopPane);
setupDesktopExportFrame(); setupDesktopExportFrame();
setupProfiler();
setupFullscreenToggle(); setupFullscreenToggle();
setupBlackBg(); setupBlackBg();
@@ -59,6 +61,17 @@ public class SwingIFrame {
); );
} }
private void setupProfiler() {
desktopIconManager.addIcon(
"Profiler",
IconSetter.getDbg_icon(),
() -> {
SwingUtilities.invokeLater(() -> {
Profiler.showFrame(new Profiler(mainFrame));
});
});
}
public void addCameraInternalFrame(Webcam webcam) { public void addCameraInternalFrame(Webcam webcam) {
CameraInternalFrame cameraFrame = new CameraInternalFrame(webcam, this::handleEffectsRequest); CameraInternalFrame cameraFrame = new CameraInternalFrame(webcam, this::handleEffectsRequest);

View File

@@ -2,20 +2,25 @@ package io.swtc.proccessing.ui;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.Objects; import java.util.Objects;
/* vital boilerplate class, shouldve made it better but idk. */
public class IconSetter { public class IconSetter {
private static Image ICON_IMAGE; private static Image ICON_IMAGE;
private static ImageIcon ICON_ICON; private static ImageIcon ICON_ICON;
private static Image effects_icon; private static Image effects_icon;
private static ImageIcon dbg_icon;
/* this is used for the app icon itself (the one in tb) */
public static Image getIcon() { public static Image getIcon() {
if (ICON_IMAGE == null) { if (ICON_IMAGE == null) {
URL url = IconSetter.class.getResource("/icons/artwork.png"); URL url = IconSetter.class.getResource("/icons/artwork.png");
if (url == null) throw new RuntimeException("Icon not found: /icons/artwork.png"); if (Objects.isNull(url)) {
ShowError.error(null,"Icon","Icon (Type: Image) failed, NULL!");
throw new RuntimeException("NULL!");
}
ICON_IMAGE = Toolkit.getDefaultToolkit().getImage(url); ICON_IMAGE = Toolkit.getDefaultToolkit().getImage(url);
} }
return ICON_IMAGE; return ICON_IMAGE;
@@ -24,7 +29,10 @@ public class IconSetter {
public static Image getEffectIcon() { public static Image getEffectIcon() {
if (Objects.isNull(effects_icon)) { if (Objects.isNull(effects_icon)) {
URL url = IconSetter.class.getResource("/icons/effectsframe.png"); URL url = IconSetter.class.getResource("/icons/effectsframe.png");
if (Objects.isNull(url)) ShowError.error(null,"Error","Icon not found"); if (Objects.isNull(url)) {
ShowError.error(null,"Icon","Effects icon was Null! (Type Image)");
throw new RuntimeException("NULL!");
}
effects_icon = Toolkit.getDefaultToolkit().getImage(url); effects_icon = Toolkit.getDefaultToolkit().getImage(url);
} }
return effects_icon; return effects_icon;
@@ -33,7 +41,10 @@ public class IconSetter {
public static ImageIcon getIconAsImageIcon() { public static ImageIcon getIconAsImageIcon() {
if (ICON_ICON == null) { if (ICON_ICON == null) {
URL url = IconSetter.class.getResource("/icons/artwork.png"); URL url = IconSetter.class.getResource("/icons/artwork.png");
if (url == null) throw new RuntimeException("Icon not found: /icons/artwork.png"); if (Objects.isNull(url)) {
ShowError.error(null,"Icon","Icon not found!, NULL! (Type ImageIcon)");
throw new RuntimeException("NULL!");
}
ICON_ICON = new ImageIcon(url); // separate variable for ImageIcon ICON_ICON = new ImageIcon(url); // separate variable for ImageIcon
} }
return ICON_ICON; return ICON_ICON;
@@ -42,9 +53,24 @@ public class IconSetter {
public static ImageIcon getSaveIconAsImageIcon() { public static ImageIcon getSaveIconAsImageIcon() {
if (Objects.isNull(ICON_ICON)) { if (Objects.isNull(ICON_ICON)) {
URL url = IconSetter.class.getResource("/icons/save.png"); URL url = IconSetter.class.getResource("/icons/save.png");
if (Objects.isNull(url)) throw new RuntimeException("Icon not found: /icons/save.ico"); if (Objects.isNull(url)) {
ShowError.error(null,"Icon","getSaveIconAsImageIcon failed, NULL! (Type ImageIcon)");
throw new RuntimeException("NULL!");
}
ICON_ICON = new ImageIcon(url); ICON_ICON = new ImageIcon(url);
} }
return ICON_ICON; return ICON_ICON;
} }
public static ImageIcon getDbg_icon() {
if (Objects.isNull(dbg_icon)) {
URL url = IconSetter.class.getResource("/icons/icondbg-7.png");
if (Objects.isNull(url)) {
ShowError.error(null, "Icon", "getDbg_icon, object url was null (Type ImageIcon)");
throw new RuntimeException("NULL!");
}
dbg_icon = new ImageIcon(url);
}
return dbg_icon;
}
} }

View File

@@ -0,0 +1,169 @@
package io.swtc.proccessing.ui.desktop.debug;
import io.swtc.proccessing.ui.IconSetter;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.lang.management.*;
import java.util.List;
/* simple profiler to see memory usage, this isnt too important but certainly useful */
public class Profiler extends JFrame {
private final MemoryMXBean memoryMXBean =
ManagementFactory.getMemoryMXBean();
private final ThreadMXBean threadMXBean =
ManagementFactory.getThreadMXBean();
private final List<MemoryPoolMXBean> pools =
ManagementFactory.getMemoryPoolMXBeans();
private final List<GarbageCollectorMXBean> gcs =
ManagementFactory.getGarbageCollectorMXBeans();
private final List<BufferPoolMXBean> buffers =
ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
private final JLabel heapLabel = new JLabel();
private final JLabel nonHeapLabel = new JLabel();
private final JLabel threadLabel = new JLabel();
private final DefaultTableModel poolModel =
new DefaultTableModel(
new String[]{"Pool", "Type", "Used (MB)", "Committed (MB)", "Max (MB)"},
0
);
private final DefaultTableModel gcModel =
new DefaultTableModel(
new String[]{"GC", "Collections", "Time (ms)"},
0
);
private final DefaultTableModel bufferModel =
new DefaultTableModel(
new String[]{"Buffer", "Used (MB)", "Count"},
0
);
public Profiler(JFrame parent) {
setTitle("Profiler");
setSize(750, 400);
setLocationRelativeTo(parent);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
ImageIcon ico = IconSetter.getDbg_icon();
setIconImage(ico.getImage());
JPanel root = new JPanel(new BorderLayout(10, 10));
root.setBorder(new EmptyBorder(10, 10, 10, 10));
setContentPane(root);
JPanel summary = new JPanel();
summary.setLayout(new BoxLayout(summary, BoxLayout.Y_AXIS));
summary.add(heapLabel);
summary.add(nonHeapLabel);
summary.add(threadLabel);
root.add(summary, BorderLayout.NORTH);
JTabbedPane tabs = new JTabbedPane();
tabs.add("Memory Pools", new JScrollPane(new JTable(poolModel)));
tabs.add("GC", new JScrollPane(new JTable(gcModel)));
tabs.add("Buffers", new JScrollPane(new JTable(bufferModel)));
root.add(tabs, BorderLayout.CENTER);
Timer timer = new Timer(1000, e -> update());
timer.start();
update();
}
private void update() {
updateSummary();
updatePools();
updateGC();
updateBuffers();
}
private void updateSummary() {
MemoryUsage heap = memoryMXBean.getHeapMemoryUsage();
MemoryUsage nonHeap = memoryMXBean.getNonHeapMemoryUsage();
heapLabel.setText(String.format(
"Heap: used %d MB / committed %d MB / max %d MB",
mb(heap.getUsed()),
mb(heap.getCommitted()),
mb(heap.getMax())
));
nonHeapLabel.setText(String.format(
"Non-Heap: used %d MB / committed %d MB",
mb(nonHeap.getUsed()),
mb(nonHeap.getCommitted())
));
int threads = threadMXBean.getThreadCount();
int peak = threadMXBean.getPeakThreadCount();
int daemons = threadMXBean.getDaemonThreadCount();
threadLabel.setText(String.format(
"Threads: %d live (%d daemon, peak %d)",
threads, daemons, peak
));
}
private void updatePools() {
poolModel.setRowCount(0);
for (MemoryPoolMXBean pool : pools) {
MemoryUsage u = pool.getUsage();
if (u == null) continue;
poolModel.addRow(new Object[]{
pool.getName(),
pool.getType(),
mb(u.getUsed()),
mb(u.getCommitted()),
mb(u.getMax())
});
}
}
private void updateGC() {
gcModel.setRowCount(0);
for (GarbageCollectorMXBean gc : gcs) {
gcModel.addRow(new Object[]{
gc.getName(),
gc.getCollectionCount(),
gc.getCollectionTime()
});
}
}
private void updateBuffers() {
bufferModel.setRowCount(0);
for (BufferPoolMXBean b : buffers) {
bufferModel.addRow(new Object[]{
b.getName(),
mb(b.getMemoryUsed()),
b.getCount()
});
}
}
/* Conversion logic for byte -> mb */
public long mb(long bytes) {
return bytes < 0 ? -1 : bytes / 1024 / 1024;
}
public static void showFrame(JFrame parent) {
SwingUtilities.invokeLater(() ->
new Profiler(parent).setVisible(true)
);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB