stabilisation #2
33
readme.md
33
readme.md
@@ -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):
|
||||||
|
|||||||
@@ -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 */ }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
169
src/main/java/io/swtc/proccessing/ui/desktop/debug/Profiler.java
Normal file
169
src/main/java/io/swtc/proccessing/ui/desktop/debug/Profiler.java
Normal 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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/main/resources/icons/icondbg-7.png
Normal file
BIN
src/main/resources/icons/icondbg-7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Reference in New Issue
Block a user