Change SBC to Jetson Orin

This commit is contained in:
2025-02-25 07:35:38 +07:00
parent 21e8ab1e82
commit ce5c8d5946
16 changed files with 1057 additions and 80 deletions

View File

@@ -4,6 +4,7 @@
<inspection_tool class="ExtractMethodRecommender" enabled="true" level="WARNING" enabled_by_default="true"> <inspection_tool class="ExtractMethodRecommender" enabled="true" level="WARNING" enabled_by_default="true">
<option name="minLength" value="745" /> <option name="minLength" value="745" />
</inspection_tool> </inspection_tool>
<inspection_tool class="GrazieInspection" enabled="false" level="GRAMMAR_ERROR" enabled_by_default="false" />
<inspection_tool class="HttpUrlsUsage" enabled="true" level="WEAK WARNING" enabled_by_default="true"> <inspection_tool class="HttpUrlsUsage" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredUrls"> <option name="ignoredUrls">
<list> <list>
@@ -35,6 +36,7 @@
</list> </list>
</option> </option>
</inspection_tool> </inspection_tool>
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MethodNameSameAsClassName" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="MethodNameSameAsClassName" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantCast" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="RedundantCast" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">

View File

@@ -134,8 +134,8 @@
</a> </a>
</div> </div>
<div class="col"> <div class="col">
<a> <a onmousedown="send_stop_movement()">
<i id="btn_center" class="btn-nav-center fa-solid fa-circle"></i> <i id="btn_center" class="btn-nav-center fa-solid fa-circle" title="Stop Movement"></i>
</a> </a>
</div> </div>
<div class="col"> <div class="col">

80
onnx/coco.names Normal file
View File

@@ -0,0 +1,80 @@
person
bicycle
car
motorbike
aeroplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
sofa
pottedplant
bed
diningtable
toilet
tvmonitor
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush

BIN
onnx/yolov8n.onnx Normal file

Binary file not shown.

26
pom.xml
View File

@@ -178,32 +178,6 @@
<version>5.1.2-1.5.8</version> <version>5.1.2-1.5.8</version>
<classifier>linux-arm64</classifier> <classifier>linux-arm64</classifier>
</dependency> </dependency>
<!-- manual tambah untuk platform linux-x86_64
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.9.0-1.5.10</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.10</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.26-1.5.10</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.1.1-1.5.10</version>
<classifier>linux-x86_64</classifier>
</dependency>
-->
<dependency> <dependency>
<groupId>com.corundumstudio.socketio</groupId> <groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId> <artifactId>netty-socketio</artifactId>

View File

@@ -9,6 +9,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.opencv.opencv_core.Mat;
import org.tinylog.Logger; import org.tinylog.Logger;
public class GrabbingTask implements Runnable { public class GrabbingTask implements Runnable {
@@ -23,6 +24,8 @@ public class GrabbingTask implements Runnable {
@Setter private Consumer<Frame> onLQFrameUpdate; @Setter private Consumer<Frame> onLQFrameUpdate;
@Setter private Consumer<String> onHQBase64Update; @Setter private Consumer<String> onHQBase64Update;
@Setter private Consumer<String> onLQBase64Update; @Setter private Consumer<String> onLQBase64Update;
@Setter private Consumer<Frame> onYoloUpdate;
@Setter private Consumer<String> onYoloBase64Update;
// status of capture fps // status of capture fps
@Getter private int CaptureFPS = 0; @Getter private int CaptureFPS = 0;
@@ -33,6 +36,8 @@ public class GrabbingTask implements Runnable {
// for FPS calculation // for FPS calculation
private int intendedFps = 10; private int intendedFps = 10;
private final YoloDetector yolo;
@SuppressWarnings("SameParameterValue") @SuppressWarnings("SameParameterValue")
private void updateMessage(String message) { private void updateMessage(String message) {
if (onMessageUpdate != null) { if (onMessageUpdate != null) {
@@ -40,9 +45,17 @@ public class GrabbingTask implements Runnable {
} }
} }
private void updateYoloBase64(String base64) {
if (onYoloBase64Update != null) {
onYoloBase64Update.accept(base64);
}
}
private void updateYoloFrame(Frame frame) {
if (onYoloUpdate != null) {
onYoloUpdate.accept(frame);
}
}
private void updateHQBase64(String base64) { private void updateHQBase64(String base64) {
if (onHQBase64Update != null) { if (onHQBase64Update != null) {
@@ -77,6 +90,7 @@ public class GrabbingTask implements Runnable {
this.isGrabbing = isGrabbing; this.isGrabbing = isGrabbing;
this.grabber = grabber; this.grabber = grabber;
if (fps>0) intendedFps = fps; if (fps>0) intendedFps = fps;
yolo = new YoloDetector();
} }
@@ -94,6 +108,23 @@ public class GrabbingTask implements Runnable {
} else updateMessage("processFrame have null frame"); } else updateMessage("processFrame have null frame");
} }
//TODO masih trouble di sini
private void DetectYolo(Frame frame){
if (frame!=null){
try{
Mat processed = yolo.Detect(frame);
Frame yoloFrame = SomeCodes.CoreMatConverter.convert(processed);
updateYoloFrame(yoloFrame);
updateYoloBase64(SomeCodes.FrameToBase64(yoloFrame));
} catch (Exception e){
System.out.println("error processing YOLO, Message : "+e.getMessage());
updateYoloFrame(null);
updateYoloBase64("");
}
}
}
private void flush_grabber(){ private void flush_grabber(){
try { try {
if (grabber!=null) grabber.flush(); if (grabber!=null) grabber.flush();
@@ -117,9 +148,13 @@ public class GrabbingTask implements Runnable {
Thread.yield(); Thread.yield();
Frame frame = grabber.grab(); Frame frame = grabber.grab();
if (framecount<Integer.MAX_VALUE) framecount++; else framecount = 0; if (framecount<Integer.MAX_VALUE) framecount++; else framecount = 0;
if (framecount % skippedframes == 0) processFrame(frame); if (framecount % skippedframes == 0) {
processFrame(frame);
DetectYolo(frame);
}
} catch (Exception e){ } catch (Exception e){
Logger.error("Error grabbing frame: "+e.getMessage()); Logger.error("Error grabbing frame: "+e.getMessage());
} }
long elapsed = System.currentTimeMillis() - starttick; long elapsed = System.currentTimeMillis() - starttick;

View File

@@ -70,10 +70,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) { if (isOpen()) {
Main.Max485Direction(true); Main.Max485Direction(true);
serialPort.writeBytes(command, command.length); int written = serialPort.writeBytes(command, command.length);
Main.Max485Direction(false); Main.Max485Direction(false);
Main.Blink_LedPanTilt(); Main.Blink_LedPanTilt();
} System.out.println("Stop Movement written : "+written);
} else System.out.println("Stop Movement failed, serial port not open");
} }
/** /**
@@ -89,10 +90,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) { if (isOpen()) {
Main.Max485Direction(true); Main.Max485Direction(true);
serialPort.writeBytes(command, command.length); int written = serialPort.writeBytes(command, command.length);
Main.Max485Direction(false); Main.Max485Direction(false);
Main.Blink_LedPanTilt(); Main.Blink_LedPanTilt();
} System.out.println("Pan Left written : "+written);
} else System.out.println("Pan Left failed, serial port not open");
} }
/** /**
@@ -108,10 +110,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) { if (isOpen()) {
Main.Max485Direction(true); Main.Max485Direction(true);
serialPort.writeBytes(command, command.length); int written = serialPort.writeBytes(command, command.length);
Main.Max485Direction(false); Main.Max485Direction(false);
Main.Blink_LedPanTilt(); Main.Blink_LedPanTilt();
} System.out.println("Pan Right written : "+written);
} else System.out.println("Pan Right failed, serial port not open");
} }
/** /**
@@ -127,10 +130,11 @@ public class PanTiltController {
command[0] = (byte) 0xFF; // add synchronization byte command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) { if (isOpen()) {
Main.Max485Direction(true); Main.Max485Direction(true);
serialPort.writeBytes(command, command.length); int written = serialPort.writeBytes(command, command.length);
Main.Max485Direction(false); Main.Max485Direction(false);
Main.Blink_LedPanTilt(); Main.Blink_LedPanTilt();
} System.out.println("Tilt Up written : "+written);
} else System.out.println("Tilt Up failed, serial port not open");
} }
/** /**
@@ -144,6 +148,23 @@ public class PanTiltController {
byte[] command = new byte[]{0, cameraid, 0, 16, speed, 0, 0}; byte[] command = new byte[]{0, cameraid, 0, 16, speed, 0, 0};
command[6] = Checksum(command); // add checksum command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) {
Main.Max485Direction(true);
int written = serialPort.writeBytes(command, command.length);
Main.Max485Direction(false);
Main.Blink_LedPanTilt();
System.out.println("Tilt Down written : "+written);
} else System.out.println("Tilt Down failed, serial port not open");
}
/**
* Go to Preset
* @param preset preset number
*/
public void GoToPreset(byte preset){
byte[] command = new byte[]{0, cameraid, 0, 15, preset, 0, 0};
command[6] = Checksum(command); // add checksum
command[0] = (byte) 0xFF; // add synchronization byte
if (isOpen()) { if (isOpen()) {
Main.Max485Direction(true); Main.Max485Direction(true);
serialPort.writeBytes(command, command.length); serialPort.writeBytes(command, command.length);

View File

@@ -3,6 +3,7 @@ import lombok.Getter;
import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.global.opencv_core;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.tinylog.Logger; import org.tinylog.Logger;
@@ -17,8 +18,10 @@ public class RtspGrabber {
private final AtomicBoolean isGrabbing = new AtomicBoolean(false); private final AtomicBoolean isGrabbing = new AtomicBoolean(false);
private Frame lastHQFrame = null; private Frame lastHQFrame = null;
private Frame lastLQFrame = null; private Frame lastLQFrame = null;
private Frame lastYoloFrame = null;
private String lastHQBase64 = null; private String lastHQBase64 = null;
private String lastLQBase64 = null; private String lastLQBase64 = null;
private String lastYoloBase64 = null;
private @Getter int HQWidth = 0; private @Getter int HQWidth = 0;
private @Getter int HQHeight = 0; private @Getter int HQHeight = 0;
private @Getter int LQWidth = 0; private @Getter int LQWidth = 0;
@@ -26,6 +29,13 @@ public class RtspGrabber {
private GrabbingTask grabbingTask; private GrabbingTask grabbingTask;
public RtspGrabber(String ip, String path) { public RtspGrabber(String ip, String path) {
int cudacount = opencv_core.getCudaEnabledDeviceCount();
if (cudacount>0){
Logger.info("CUDA enabled devices found: " + cudacount);
opencv_core.printCudaDeviceInfo(0);
} else {
Logger.info("No CUDA enabled devices found");
}
this.rtspUrl = "rtsp://" + ip + path; this.rtspUrl = "rtsp://" + ip + path;
Logger.info("RtspGrabber created with url: " + rtspUrl); Logger.info("RtspGrabber created with url: " + rtspUrl);
} }
@@ -62,6 +72,22 @@ public class RtspGrabber {
return lastLQBase64; return lastLQBase64;
} }
private synchronized void setLastYoloBase64(String base64){
lastYoloBase64 = base64;
}
public synchronized String getLastYoloBase64(){
return lastYoloBase64;
}
private synchronized void setLastYoloFrame(Frame frame){
lastYoloFrame = frame;
}
public synchronized Frame getLastYoloFrame(){
return lastYoloFrame;
}
/** /**
* Start grabbing frames from rtsp * Start grabbing frames from rtsp
* @param useTcp Use tcp instead of udp * @param useTcp Use tcp instead of udp
@@ -143,6 +169,8 @@ public class RtspGrabber {
}); });
tt.setOnHQBase64Update(this::setLastHQBase64); tt.setOnHQBase64Update(this::setLastHQBase64);
tt.setOnLQBase64Update(this::setLastLQBase64); tt.setOnLQBase64Update(this::setLastLQBase64);
tt.setOnYoloUpdate(this::setLastYoloFrame);
tt.setOnYoloBase64Update(this::setLastYoloBase64);
return tt; return tt;
} }
} }

View File

@@ -0,0 +1,167 @@
package Camera;
import Other.SomeCodes;
import lombok.Getter;
import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.global.opencv_dnn;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Rect;
import org.bytedeco.opencv.opencv_core.Scalar;
import org.bytedeco.opencv.opencv_core.Size;
import org.bytedeco.opencv.opencv_dnn.*;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfRect2d;
import org.opencv.dnn.Dnn;
import java.io.BufferedReader;
import java.io.FileReader;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.bytedeco.opencv.global.opencv_core.CV_32F;
public class YoloDetector {
private Net net;
private @Getter boolean NetLoaded;
private List<String> classes ;
// YOLO expect image in 640 x 640
private final int input_width = 640;
private final int input_height = 640;
// minimum confidence for detections
private final float confidence_threshold = 0.5f;
// Non-maximum suppression threshold
private final float nms_threshold = 0.4f;
public YoloDetector() {
NetLoaded = false;
net = null;
classes = null;
String onnxfile = SomeCodes.ExtractResource("/yolov8n.onnx", SomeCodes.currentDirectory);
String namesfile = SomeCodes.ExtractResource("/coco.names", SomeCodes.currentDirectory);
if (SomeCodes.ValidFile(onnxfile)){
if (SomeCodes.ValidFile(namesfile)){
net = opencv_dnn.readNetFromONNX(onnxfile);
net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV);
net.setPreferableTarget(Dnn.DNN_TARGET_CPU);
classes = new ArrayList<>();
try(BufferedReader br = new BufferedReader(new FileReader(namesfile))) {
String line;
while ((line = br.readLine()) != null) {
classes.add(line);
}
} catch (Exception e){
System.out.println("Error: reading names file");
}
if (!net.empty()){
if (!classes.isEmpty()){
NetLoaded = true;
} else System.out.println("Error: names file is empty");
} else System.out.println("Error: net is empty");
} else System.out.println("Error: names file not found");
} else System.out.println("Error: onnx file not found");
}
public Mat Detect(Frame frame){
Mat mat = SomeCodes.CoreMatConverter.convertToMat(frame);
return Detect(mat);
}
public Mat Detect(Mat frame){
if (NetLoaded){
Mat blob = opencv_dnn.blobFromImage(frame, 1.0/255.0, new Size(input_width, input_height), new Scalar(0) , true, false, CV_32F);
net.setInput(blob);
Mat detections = net.forward();
return detections;
} else {
System.out.println("Error: Net not loaded");
return new Mat();
}
}
private Mat ProcessDetection(Mat frame, Mat output){
int rows = output.rows();
int cols = output.cols();
List<Rect> boxes = new ArrayList<>();
List<Float> confidences = new ArrayList<>();
List<Integer> classIds = new ArrayList<>();
for(int i=0;i<rows;i++){
Mat row = output.row(i);
float confidence = row.getFloatBuffer().get(4);
if (confidence >= confidence_threshold){
FloatBuffer data = row.getFloatBuffer();
int classid = 0;
float maxscore = 0;
for(int j = 5; j< cols; j++){
float score = data.get(j);
if (score > maxscore){
maxscore = score;
classid = j-5;
}
}
if (maxscore>= confidence_threshold){
int x = (int)(data.get(0) * frame.cols());
int y = (int)(data.get(1) * frame.rows());
int width = (int)(data.get(2) * frame.cols());
int height = (int)(data.get(3) * frame.rows());
boxes.add(new Rect(x-width/2, y-height/2, width, height));
confidences.add(maxscore);
classIds.add(classid);
}
}
}
Rect[] rr = new Rect[boxes.size()];
for(int ii = 0; ii<boxes.size(); ii++){
rr[ii] = boxes.get(ii);
}
MatOfRect2d rects = new MatOfRect2d(ListToRectArray(boxes));
MatOfFloat conf = new MatOfFloat(ListToArray(confidences));
MatOfInt indices = new MatOfInt();
if (!boxes.isEmpty()){
Dnn.NMSBoxes(rects, conf, confidence_threshold, nms_threshold, indices);
}
int[] idx = indices.toArray();
for(int i : idx){
Rect box = boxes.get(i);
int classId = classIds.get(i);
float confidence = confidences.get(i);
String label = classes.get(classId);
opencv_imgproc.rectangle(frame, box, Scalar.RED);
}
return frame;
}
private org.opencv.core.Rect2d[] ListToRectArray(List<Rect> list){
org.opencv.core.Rect2d[] arr = new org.opencv.core.Rect2d[list.size()];
for(int i=0;i<list.size();i++){
Rect r = list.get(i);
arr[i] = new org.opencv.core.Rect2d(r.x(), r.y(), r.width(), r.height());
}
return arr;
}
private float[] ListToArray(List<Float> list){
float[] arr = new float[list.size()];
for(int i=0;i<list.size();i++){
arr[i] = list.get(i);
}
return arr;
}
}

View File

@@ -6,10 +6,9 @@ import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.global.opencv_core; import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_dnn;
import org.bytedeco.opencv.global.opencv_imgproc; import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat; import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_core.Size;
import org.bytedeco.opencv.opencv_core.UMat;
import org.bytedeco.opencv.opencv_java; import org.bytedeco.opencv.opencv_java;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.opencv.core.MatOfByte; import org.opencv.core.MatOfByte;
@@ -184,6 +183,20 @@ public class SomeCodes {
return ""; return "";
} }
public static String MatToBase64(org.opencv.core.Mat mat){
if (mat!=null){
if (!mat.empty()){
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(".jpg", mat, mob);
byte[] jpgdata = mob.toArray();
mob.release();
mat.release();
return base64encoder.encodeToString(jpgdata);
}
}
return "";
}
// Function ini pakai opencv, bukan javacv, jadi perlu Loader.load(opencv_java.class) di awal // Function ini pakai opencv, bukan javacv, jadi perlu Loader.load(opencv_java.class) di awal
// lebih optimal untuk konversi frame ke base64 // lebih optimal untuk konversi frame ke base64
@@ -191,14 +204,7 @@ public class SomeCodes {
if (frame!=null){ if (frame!=null){
org.opencv.core.Mat converted = CoreMatConverter.convert(frame); org.opencv.core.Mat converted = CoreMatConverter.convert(frame);
if (converted!=null){ if (converted!=null){
if (!converted.empty()){ return MatToBase64(converted);
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(".jpg", converted, mob);
byte[] jpgdata = mob.toArray();
mob.release();
converted.release();
return base64encoder.encodeToString(jpgdata);
}
} }
} }
return ""; return "";
@@ -283,4 +289,106 @@ public class SomeCodes {
} }
return false; return false;
} }
public static void Sleep(int milliseconds){
try{
Thread.sleep(milliseconds);
} catch (Exception e){
Logger.error("Error sleeping: "+e.getMessage());
}
}
public static Mat ResizeForYolo(Mat image) {
int targetSize = 640; // YOLOv8 input size (640x640)
// Get original dimensions
int originalWidth = image.cols();
int originalHeight = image.rows();
// Compute new dimensions while keeping aspect ratio
float scale = Math.min((float) targetSize / originalWidth, (float) targetSize / originalHeight);
int newWidth = Math.round(originalWidth * scale);
int newHeight = Math.round(originalHeight * scale);
// Resize while keeping aspect ratio
Mat resizedImage = new Mat();
opencv_imgproc.resize(image, resizedImage, new Size(newWidth, newHeight));
// Create a black 640x640 image and place the resized image in the center (padding)
Mat paddedImage = new Mat(targetSize, targetSize, image.type(), new Scalar(0, 0, 0,0));
int xOffset = (targetSize - newWidth) / 2;
int yOffset = (targetSize - newHeight) / 2;
Rect roi = new Rect(xOffset, yOffset, newWidth, newHeight);
Mat regionOfInterest = paddedImage.apply(roi);
resizedImage.copyTo(regionOfInterest);
// Convert to blob (normalize to [0,1])
//Mat blob = new Mat();
//opencv_dnn.blobFromImage(paddedImage, blob, 1.0 / 255.0, new Size(targetSize, targetSize), new Scalar(0, 0, 0), true, false);
return paddedImage;
}
public static Mat preprocessForYOLO(Mat image) {
int targetSize = 640; // YOLO input size
// Original size
int originalWidth = image.cols();
int originalHeight = image.rows();
// Scale to fit 640x640 while maintaining aspect ratio
float scale = Math.min((float) targetSize / originalWidth, (float) targetSize / originalHeight);
int newWidth = Math.round(originalWidth * scale);
int newHeight = Math.round(originalHeight * scale);
// Resize image
Mat resizedImage = new Mat();
opencv_imgproc.resize(image, resizedImage, new Size(newWidth, newHeight));
// Create black canvas (640x640)
Mat paddedImage = new Mat(targetSize, targetSize, image.type(), new Scalar());
// Center the resized image on the black background
int xOffset = (targetSize - newWidth) / 2;
int yOffset = (targetSize - newHeight) / 2;
Rect roi = new Rect(xOffset, yOffset, newWidth, newHeight);
resizedImage.copyTo(paddedImage.apply(roi));
// Convert to blob (normalize to [0,1])
Mat blob = new Mat();
opencv_dnn.blobFromImage(paddedImage);
return blob;
}
public static Mat resizeAndPad(Frame fr, int targetWidth, int targetHeight) {
Mat image = matConverter.convertToMat(fr);
int originalWidth = image.cols();
int originalHeight = image.rows();
// Scale factor for resizing while maintaining aspect ratio
float scale = Math.min((float) targetWidth / originalWidth, (float) targetHeight / originalHeight);
int newWidth = Math.round(originalWidth * scale);
int newHeight = Math.round(originalHeight * scale);
// Resize the image
Mat resizedImage = new Mat();
opencv_imgproc.resize(image, resizedImage, new Size(newWidth, newHeight));
// Create a new black (zero-filled) Mat of target size
Mat paddedImage = new Mat(targetHeight, targetWidth, image.type(), new Scalar());
// Calculate padding
int xOffset = (targetWidth - newWidth) / 2;
int yOffset = (targetHeight - newHeight) / 2;
// Place resized image into center of the black canvas
Rect roi = new Rect(xOffset, yOffset, newWidth, newHeight);
Mat regionOfInterest = paddedImage.apply(roi);
resizedImage.copyTo(regionOfInterest);
return paddedImage;
}
} }

View File

@@ -0,0 +1,38 @@
package SBC;
import lombok.Getter;
public class I2C_BUS {
private final Linux_C_lib C = Linux_C_lib.INSTANCE;
private @Getter boolean opened = false;
private final @Getter String i2c_name;
private @Getter int i2c_handle = -1;
public I2C_BUS(int bus_number){
this.i2c_name = "/dev/i2c-"+bus_number;
}
public boolean Open_Bus(){
if (!opened){
final int O_RDWR = 0x00000002;
i2c_handle = C.open(i2c_name, O_RDWR);
if (i2c_handle>=0){
opened = true;
return true;
}
}
return false;
}
public void Close_Bus(){
if (opened){
if (i2c_handle>=0){
C.close(i2c_handle);
i2c_handle = -1;
}
opened = false;
}
}
}

View File

@@ -0,0 +1,147 @@
package SBC;
import lombok.Getter;
@SuppressWarnings("unused")
public class I2C_Device {
Linux_C_lib C = Linux_C_lib.INSTANCE;
private @Getter int bus_handle;
private @Getter int device_address;
private @Getter int dev_handle;
private @Getter boolean opened = false;
/**
* Create I2C Device
* @param bus_handle I2C Bus Handle, from opening I2C_Bus
* @param device_address I2C Device Address
*/
public I2C_Device(int bus_handle, int device_address){
opened = false;
if (bus_handle<0 || device_address<0) return;
this.bus_handle = bus_handle;
this.device_address = device_address;
}
/**
* Open I2C Device in Slave mode
* @return true if successfully opened
*/
public boolean Open_Slave(){
boolean sucess = false;
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SLAVE, device_address);
if (dev_handle>=0){
sucess = true;
}
opened = sucess;
return opened;
}
/**
* Open I2C Device in Slave mode with Force
* @return true if successfully opened
*/
public boolean Open_SlaveForce(){
boolean sucess = false;
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SLAVE_FORCE, device_address);
if (dev_handle>=0){
C.ioctl(bus_handle,I2C_Flags.I2C_RETRIES, 3);
C.ioctl(bus_handle,I2C_Flags.I2C_TIMEOUT, 1000);
sucess = true;
}
opened = sucess;
return opened;
}
/**
* Open I2C Device in Read Write mode
* @return true if successfully opened
*/
public boolean Open_RDWR(){
boolean sucess = false;
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_RDWR, device_address);
if (dev_handle>=0){
sucess = true;
}
opened = sucess;
return opened;
}
/**
* Open I2C Device in SMBus mode
* @return true if successfully opened
*/
public boolean Open_SMBus(){
boolean sucess = false;
dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SMBUS, device_address);
if (dev_handle>=0){
sucess = true;
}
opened = sucess;
return opened;
}
/**
* Close I2C Device
*/
public void Close(){
C.close(dev_handle);
opened = false;
dev_handle = -1;
}
/**
* Write Bytes to I2C Device
* @param data bytes to write
* @return number of bytes written
*/
public int WriteBytes(byte[] data){
if (bus_handle<0 || dev_handle<0 || device_address<0) return -1;
return C.write(bus_handle, data, data.length);
}
/**
* Write Byte to I2C Device
* @param register_address register address
* @param data byte to write
* @return number of bytes written
*/
public int WriteBytes(int register_address, byte data){
byte[] cmd = new byte[2];
cmd[0] = (byte) register_address;
cmd[1] = data;
return WriteBytes(cmd);
}
/**
* Write Bytes to I2C Device
* @param register_address register address
* @param data bytes to write
* @return number of bytes written
*/
public int WriteBytes(int register_address, byte[] data){
byte[] cmd = new byte[data.length+1];
cmd[0] = (byte) register_address;
System.arraycopy(data, 0, cmd, 1, data.length);
return WriteBytes(cmd);
}
/**
* Read Bytes from I2C Device
* @param readsize number of bytes to read
* @return bytes read
*/
public byte[] ReadBytes(int readsize){
if (bus_handle<0 || dev_handle<0 || device_address<0) return null;
byte[] data = new byte[readsize];
int read = C.read(bus_handle, data, readsize);
if (read<0) return null;
if (read<readsize){
byte[] temp = new byte[read];
System.arraycopy(data, 0, temp, 0, read);
return temp;
}
return data;
}
}

View File

@@ -0,0 +1,13 @@
package SBC;
public class I2C_Flags {
public final static int I2C_RETRIES = 0x701; /* number of times a device address should be polled when not acknowledging */
public final static int I2C_TIMEOUT = 0x702; /* set timeout in units of 10 ms */
public final static int I2C_SLAVE = 0x703; /* Command at ioctl, means : Use this slave address */
public final static int I2C_TENBIT = 0x704; /* 0 for 7 bit addrs, != 0 for 10 bit */
public final static int I2C_FUNCS = 0x705; /* Command at ioctl, means : Get the adapter functionality */
public final static int I2C_SLAVE_FORCE = 0x706; /* Command at ioctl, means : Use this slave address, even if it is already in use by a driver! */
public final static int I2C_RDWR = 0x707; /* Command at ioctl, means : Combined R/W transfer (one stop only) */
public final static int I2C_PEC = 0x708; /* != 0 to use PEC with SMBus */
public final static int I2C_SMBUS = 0x720; /* SMBus transfer */
}

View File

@@ -0,0 +1,69 @@
package SBC;
import java.util.Arrays;
import java.util.List;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
public interface Linux_C_lib extends com.sun.jna.Library {
Linux_C_lib INSTANCE = (Linux_C_lib) Native.load("c", Linux_C_lib.class);
long memcpy(int[] dst, short[] src, long n);
int memcpy(int[] dst, short[] src, int n);
int pipe(int[] fds);
int tcdrain(int fd);
int fcntl(int bus_handle, int command, int args);
int ioctl(int bus_handle, int command, int args);
int ioctl(int bus_handle, int command, int... args);
int ioctl(int bus_handle, int command, Pointer args);
int open(String path, int flags);
int close(int fd);
int write(int bus_handle, byte[] buffer, int count);
int read(int bus_handle, byte[] buffer, int count);
long write(int bus_handle, byte[] buffer, long count);
long read(int bus_handle, byte[] buffer, long count);
int select(int n, int[] read, int[] write, int[] error, timeval timeout);
int poll(int[] fds, int nfds, int timeout);
int tcflush(int fd, int qs);
void perror(String msg);
int tcsendbreak(int fd, int duration);
public class timeval extends Structure {
public NativeLong tv_sec;
public NativeLong tv_usec;
protected List<String> getFieldOrder() {
return Arrays.asList(//
"tv_sec",//
"tv_usec"//
);
}
public timeval(long second, long usecond) {
tv_sec = new NativeLong(second);
tv_usec = new NativeLong(usecond);
}
}
}

View File

@@ -0,0 +1,159 @@
package SBC;
import lombok.Getter;
@SuppressWarnings("unused")
public class PCF8574 extends I2C_Device{
private byte data = 0x00;
private final @Getter String[] pinNames = new String[8];
/**
* Create new PCF8574
* @param bus_number I2C Bus Number
* @param address PCF8574 Address
*/
public PCF8574(int bus_number, int address){
super(bus_number, address);
for(int i=0; i<8; i++){
pinNames[i] = i+"";
}
}
/**
* Set new Pin Name
* @param pin pin number, 0-7
* @param name new name
*/
public void setPinName(int pin, String name){
if (pin<0 || pin>7) return;
pinNames[pin] = name;
}
/**
* Get Pin Name
* @param pin pin number, 0-7
* @return pin name, or null if not available
*/
public String getPinName(int pin){
if (pin<0 || pin>7) return null;
return pinNames[pin];
}
/**
* Set All Pins High
* @return true if successful
*/
public boolean AllOn(){
if (super.isOpened()){
if (super.WriteBytes(new byte[]{(byte)0xFF})>0){
data = (byte)0xFF;
return true;
}
}
return false;
}
/**
* Set all Pins Low
* @return true if successful
*/
public boolean AllOff(){
if (super.isOpened()){
if (super.WriteBytes(new byte[]{(byte)0x00})>0){
data = (byte)0x00;
return true;
}
}
return false;
}
/**
* Set Pin by Pin Name
* @param pinName pin name
* @return true if successful
*/
public boolean SetPin(String pinName){
for(int i=0; i<8; i++){
if (pinNames[i].equals(pinName)){
return SetPin(i);
}
}
return false;
}
/**
* Set Pin High
* @param pin pin number 0-7
* @return true if successful
*/
public boolean SetPin(int pin){
if (pin<0 || pin>7) return false;
if (super.isOpened()){
byte temp = (byte) (data | (1<<pin));
return super.WriteBytes(new byte[]{temp})>0;
}
return false;
}
/**
* Clear Pin by Pin Name
* @param pinName pin name
* @return true if successful
*/
public boolean ClearPin(String pinName){
for(int i=0; i<8; i++){
if (pinNames[i].equals(pinName)){
return ClearPin(i);
}
}
return false;
}
/**
* Set Pin Low
* @param pin pin number 0-7
* @return true if successful
*/
public boolean ClearPin(int pin){
if (pin<0 || pin>7) return false;
if (super.isOpened()){
byte temp = (byte) (data & ~(1<<pin));
return super.WriteBytes(new byte[]{temp})>0;
}
return false;
}
/**
* Read Pin by Pin Name
* @param pinName pin name
* @return 1 if high, 0 if low, -1 if error
*/
public int ReadPin(String pinName){
for(int i=0; i<8; i++){
if (pinNames[i].equals(pinName)){
return ReadPin(i);
}
}
return -1;
}
/**
* Read Pin
* @param pin pin to read, 0 - 7
* @return 1 if high, 0 if low, -1 if error
*/
public int ReadPin(int pin){
if (pin<0 || pin>7) return -1;
if (super.isOpened()){
byte[] buffer = super.ReadBytes(1);
byte masker = (byte) (1<<pin);
return (buffer[0] & masker) > 0 ? 1 : 0;
}
return -1;
}
}

View File

@@ -11,6 +11,7 @@ import Other.SomeCodes;
import SBC.*; import SBC.*;
import Web.*; import Web.*;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.sun.jna.Platform;
import org.bytedeco.opencv.global.opencv_core; import org.bytedeco.opencv.global.opencv_core;
import org.tinylog.Logger; import org.tinylog.Logger;
@@ -45,6 +46,9 @@ public class Main {
private static ExecutorService gpioExecutor = null; private static ExecutorService gpioExecutor = null;
private static I2C_BUS i2c_bus = null;
private static PCF8574 pcf8574 = null;
// Application start from here // Application start from here
public static void main(String[] args) { public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> {
@@ -70,10 +74,16 @@ public class Main {
if (Max485Direction!=null) { if (Max485Direction!=null) {
Logger.info("GPIO pin {} unexport : {}", Max485Direction.pin, GPIO.UnexportPin(Max485Direction)); Logger.info("GPIO pin {} unexport : {}", Max485Direction.pin, GPIO.UnexportPin(Max485Direction));
} }
if (pcf8574!=null){
pcf8574.Close();
}
})); }));
init_gpio(); System.out.println("Current Directory : "+currentDirectory);
//init_gpio();
init_pcf8574();
init_system_monitoring(); init_system_monitoring();
init_properties(); init_properties();
@@ -81,12 +91,40 @@ public class Main {
init_Vapix(); init_Vapix();
init_audio(); init_audio();
init_pantiltcontroller(); init_pantiltcontroller();
init_webserver(); init_webserver();
init_rtspgrabber(); init_rtspgrabber();
} }
private static void init_pcf8574(){
if (Platform.isLinux()){
i2c_bus = new I2C_BUS(7);
if (i2c_bus.Open_Bus()){
Logger.info("I2C Bus opened");
pcf8574 = new PCF8574(i2c_bus.getI2c_handle(), 0x27);
if (pcf8574.Open_Slave()){
System.out.println("PCF8574 opened");
pcf8574.AllOff();
pcf8574.setPinName(0, "Amplifier Power");
pcf8574.setPinName(1, "Led Web");
pcf8574.setPinName(2, "Led IP Camera");
pcf8574.setPinName(3, "Led Pan Tilt");
pcf8574.setPinName(4, "Max485 Direction");
gpioExecutor = Executors.newVirtualThreadPerTaskExecutor();
} else {
System.out.println("Failed to open PCF8574");
}
} else {
System.out.println("Failed to open I2C Bus");
}
} else System.out.println("PCF8574 not supported on this platform");
}
private static void init_gpio(){ private static void init_gpio(){
if (Platform.isLinux()){
if (GPIO.HaveGPIO()){ if (GPIO.HaveGPIO()){
gpioExecutor = Executors.newVirtualThreadPerTaskExecutor(); gpioExecutor = Executors.newVirtualThreadPerTaskExecutor();
AmplifierPower = InitializePin(JetsonOrinPins.Pin13, true); AmplifierPower = InitializePin(JetsonOrinPins.Pin13, true);
@@ -94,7 +132,13 @@ public class Main {
LedIpCamera = InitializePin(JetsonOrinPins.Pin19, true); LedIpCamera = InitializePin(JetsonOrinPins.Pin19, true);
LedPanTilt = InitializePin(JetsonOrinPins.Pin21, true); LedPanTilt = InitializePin(JetsonOrinPins.Pin21, true);
Max485Direction = InitializePin(JetsonOrinPins.Pin23, true); Max485Direction = InitializePin(JetsonOrinPins.Pin23, true);
GPIO.SetValue(AmplifierPower,false);
GPIO.SetValue(LedWeb,false);
GPIO.SetValue(LedIpCamera,false);
GPIO.SetValue(LedPanTilt,false);
GPIO.SetValue(Max485Direction,false);
} }
} else System.out.println("GPIO not supported on this platform");
} }
@@ -121,17 +165,65 @@ public class Main {
public static void Max485Direction(boolean isTransmit){ public static void Max485Direction(boolean isTransmit){
if (Max485Direction!=null){ if (Max485Direction!=null){
GPIO.SetValue(Max485Direction, isTransmit); GPIO.SetValue(Max485Direction, isTransmit);
} else if (pcf8574!=null && pcf8574.isOpened()){
if (isTransmit){
pcf8574.SetPin("Max485 Direction");
} else {
pcf8574.ClearPin("Max485 Direction");
}
} }
} }
// dipanggil di PanTiltController, maka perlu public dan static // dipanggil di PanTiltController, maka perlu public dan static
public static void Blink_LedPanTilt(){ public static void Blink_LedPanTilt(){
if (LedPanTilt!=null){
Blink(LedPanTilt); Blink(LedPanTilt);
} else if (pcf8574!=null && pcf8574.isOpened()){
Blink("Led Pan Tilt");
}
}
public static void Blink_LedWeb(){
if (LedWeb!=null){
Blink(LedWeb);
} else if (pcf8574!=null && pcf8574.isOpened()){
Blink("Led Web");
}
}
public static void Blink_LedIpCamera(){
if (LedIpCamera!=null){
Blink(LedIpCamera);
} else if (pcf8574!=null && pcf8574.isOpened()){
Blink("Led IP Camera");
}
} }
private static void AmplifierControl(boolean isON){ private static void AmplifierControl(boolean isON){
if (AmplifierPower!=null){ if (AmplifierPower!=null){
GPIO.SetValue(AmplifierPower, isON); GPIO.SetValue(AmplifierPower, isON);
} else if (pcf8574!=null && pcf8574.isOpened()){
if (isON){
pcf8574.SetPin("Amplifier Power");
} else {
pcf8574.ClearPin("Amplifier Power");
}
}
}
private static void Blink(String pinName){
if (pcf8574!=null && pcf8574.isOpened()){
if (gpioExecutor!=null){
gpioExecutor.submit(()->{
pcf8574.SetPin(pinName);
try {
Thread.sleep(20);
} catch (InterruptedException ignored) {
}
pcf8574.ClearPin(pinName);
});
}
} }
} }
@@ -227,10 +319,16 @@ public class Main {
private static void init_Vapix(){ private static void init_Vapix(){
Properties config = SomeCodes.LoadProperties("config.properties"); Properties config = SomeCodes.LoadProperties("config.properties");
System.out.println("Saved Configuration for Camera");
String ip = config.getProperty("Camera_ip"); String ip = config.getProperty("Camera_ip");
String port = config.getProperty("Camera_port"); String port = config.getProperty("Camera_port");
String username = config.getProperty("Camera_user"); String username = config.getProperty("Camera_user");
String password = config.getProperty("Camera_password"); String password = config.getProperty("Camera_password");
System.out.println("Camera IP : "+ip);
System.out.println("Camera Port : "+port);
System.out.println("Camera Username : "+username);
System.out.println("Camera Password : "+password);
if (ValidString(ip)){ if (ValidString(ip)){
if (ValidPortNumber(port)){ if (ValidPortNumber(port)){
if (ValidString(username)){ if (ValidString(username)){
@@ -246,7 +344,7 @@ public class Main {
} else Logger.error("PTZ Disabled"); } else Logger.error("PTZ Disabled");
Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom()); Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom());
Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom()); Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom());
Blink(LedIpCamera); Blink_LedIpCamera();
} else Logger.error("Failed to query camera"); } else Logger.error("Failed to query camera");
} else Logger.error("Camera IP is not reachable"); } else Logger.error("Camera IP is not reachable");
} else Logger.error("Camera Password is not valid string"); } else Logger.error("Camera Password is not valid string");
@@ -255,15 +353,42 @@ public class Main {
} else Logger.error( "Camera IP is not valid string"); } else Logger.error( "Camera IP is not valid string");
} }
private static void test_pantiltcontroller(){
System.out.println("Pan Tilt Controller Test");
panTiltController.PanLeft((byte)0x20);
System.out.println("Pan Left");
Sleep(2000);
panTiltController.PanRight((byte)0x20);
System.out.println("Pan Right");
Sleep(2000);
panTiltController.StopMovement();
System.out.println("Stop Movement");
panTiltController.TiltUp((byte)0x20);
System.out.println("Tilt Up");
Sleep(2000);
panTiltController.TiltDown((byte)0x20);
System.out.println("Tilt Down");
Sleep(2000);
panTiltController.StopMovement();
System.out.println("Stop Movement");
panTiltController.GoToPreset((byte)0);
System.out.println("Go To Preset 0");
}
private static void init_pantiltcontroller() { private static void init_pantiltcontroller() {
Properties config = SomeCodes.LoadProperties("config.properties"); Properties config = SomeCodes.LoadProperties("config.properties");
String portname = config.getProperty("SerialPort"); String portname = config.getProperty("SerialPort");
String baudrate = config.getProperty("SerialBaudRate"); String baudrate = config.getProperty("SerialBaudRate");
String PanTiltID = config.getProperty("PanTiltID"); String PanTiltID = config.getProperty("PanTiltID");
Logger.info("Saved Configuration for Pan Tilt Controller");
Logger.info("Serial Port : "+portname);
Logger.info("Serial Baud Rate : "+baudrate);
Logger.info("Pan Tilt ID : "+PanTiltID);
if (ValidString(portname)){ if (ValidString(portname)){
if (ValidInteger(baudrate)){ if (ValidInteger(baudrate)){
if (ValidInteger(PanTiltID)){ if (ValidInteger(PanTiltID)){
panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID)); panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID));
if (panTiltController.isOpen()) test_pantiltcontroller();
} }
} else Logger.error("Invalid PTZ Baudrate"); } else Logger.error("Invalid PTZ Baudrate");
} else Logger.error("Invalid PTZ Port"); } else Logger.error("Invalid PTZ Port");
@@ -277,16 +402,18 @@ public class Main {
Properties config = SomeCodes.LoadProperties("config.properties"); Properties config = SomeCodes.LoadProperties("config.properties");
String targetip = config.getProperty("Camera_ip"); String targetip = config.getProperty("Camera_ip");
String rtsppath = config.getProperty("Camera_Rtsp_path"); String rtsppath = config.getProperty("Camera_Rtsp_path");
System.out.println("Camera IP : "+targetip);
System.out.println("Camera Rtsp Path : "+rtsppath);
rtspGrabber = null; rtspGrabber = null;
if (ValidString(targetip)){ if (ValidString(targetip)){
if (ValidString(rtsppath)){ if (ValidString(rtsppath)){
if (IpIsReachable(targetip)){ if (IpIsReachable(targetip)){
Logger.info("Camera IP is reachable"); Logger.info("Camera IP : "+targetip+" is reachable");
rtspGrabber = new RtspGrabber(targetip, rtsppath); rtspGrabber = new RtspGrabber(targetip, rtsppath);
rtspGrabber.Start(true, 1920, 1080); rtspGrabber.Start(true, 1920, 1080);
} else Logger.error("Camera IP is not reachable"); } else System.out.println("Camera IP : "+targetip+" is not reachable");
} else Logger.error("Camera Path is not valid string"); } else System.out.println("Camera Path : "+rtsppath+" is not valid string");
} else Logger.error("Camera IP is not valid string"); } else System.out.println("Camera IP : "+targetip+" is not valid string");
} }
private static void init_audio() { private static void init_audio() {
@@ -309,16 +436,19 @@ public class Main {
@Override @Override
public void onPlaybackStart(AudioFileProperties prop) { public void onPlaybackStart(AudioFileProperties prop) {
Logger.info("Playback started for {}", prop.filename); Logger.info("Playback started for {}", prop.filename);
AmplifierControl(true);
} }
@Override @Override
public void onPlaybackFinished(AudioFileProperties prop) { public void onPlaybackFinished(AudioFileProperties prop) {
Logger.info("Playback finished for {}", prop.filename); Logger.info("Playback finished for {}", prop.filename);
AmplifierControl(false);
} }
@Override @Override
public void onPlaybackFailure(AudioFileProperties prop, String reason) { public void onPlaybackFailure(AudioFileProperties prop, String reason) {
Logger.error("Playback failed for {}: {}", prop.filename, reason); Logger.error("Playback failed for {}: {}", prop.filename, reason);
AmplifierControl(false);
} }
@Override @Override
@@ -335,7 +465,7 @@ public class Main {
@Override @Override
public WebsocketReply onWebsocketCommand(WebsocketCommand command) { public WebsocketReply onWebsocketCommand(WebsocketCommand command) {
Blink(LedWeb); Blink_LedWeb();
byte speed; byte speed;
String cmd = command.command.toUpperCase().trim(); String cmd = command.command.toUpperCase().trim();
switch (cmd){ switch (cmd){
@@ -361,10 +491,10 @@ public class Main {
return new WebsocketReply("STOP MOVEMENT", ""); return new WebsocketReply("STOP MOVEMENT", "");
// Audio Related Commands // Audio Related Commands
case "MUTE": case "MUTE":
audioPlayer.Mute(); if (audioPlayer!=null) audioPlayer.Mute();
return new WebsocketReply("MUTE", ""); return new WebsocketReply("MUTE", "");
case "UNMUTE": case "UNMUTE":
audioPlayer.Unmute(); if (audioPlayer!=null) audioPlayer.Unmute();
return new WebsocketReply("UNMUTE", ""); return new WebsocketReply("UNMUTE", "");
case "SET VOLUME" : case "SET VOLUME" :
int volume=-1; int volume=-1;
@@ -374,11 +504,11 @@ public class Main {
if (volume>100) volume = 100; if (volume>100) volume = 100;
} }
if (volume>=0){ if (volume>=0){
audioPlayer.setPlaybackvolume(volume); if (audioPlayer!=null) audioPlayer.setPlaybackvolume(volume);
return new WebsocketReply("SET VOLUME", String.valueOf(volume)); return new WebsocketReply("SET VOLUME", String.valueOf(volume));
} else return new WebsocketReply("SET VOLUME", "Invalid Volume Value"); } else return new WebsocketReply("SET VOLUME", "Invalid Volume Value");
case "GET VOLUME" : case "GET VOLUME" :
int vol = audioPlayer.getPlaybackvolume(); int vol = audioPlayer!=null ? audioPlayer.getPlaybackvolume() : 0;
return new WebsocketReply("GET VOLUME", String.valueOf(vol)); return new WebsocketReply("GET VOLUME", String.valueOf(vol));
case "PLAY AUDIO" : case "PLAY AUDIO" :
if (ValidInteger(command.data)){ if (ValidInteger(command.data)){
@@ -391,7 +521,7 @@ public class Main {
if (afp!=null){ if (afp!=null){
audioFileProperties = afp; audioFileProperties = afp;
audioPlayer.PlayAudioFile(afp, true, pe); audioPlayer.PlayAudioFile(afp, true, pe);
AmplifierControl(true); //AmplifierControl(true);
return new WebsocketReply("PLAY AUDIO", afp.filename); return new WebsocketReply("PLAY AUDIO", afp.filename);
} else return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename); } else return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename);
@@ -403,18 +533,18 @@ public class Main {
audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file
String filename = audioFileProperties.filename; String filename = audioFileProperties.filename;
audioFileProperties = null; audioFileProperties = null;
AmplifierControl(false); //AmplifierControl(false);
return new WebsocketReply("STOP AUDIO", filename); return new WebsocketReply("STOP AUDIO", filename);
} else return new WebsocketReply("STOP AUDIO", "No audioFileProperties"); } else return new WebsocketReply("STOP AUDIO", "No audioFileProperties");
// ZOOM Related Commands // ZOOM Related Commands
case "GET MAX ZOOM": case "GET MAX ZOOM":
if (vapixProtocol!=null){ if (vapixProtocol!=null){
Blink(LedIpCamera); Blink_LedIpCamera();
return new WebsocketReply("GET MAX ZOOM", String.valueOf(vapixProtocol.GetPTZMaxZoom())); return new WebsocketReply("GET MAX ZOOM", String.valueOf(vapixProtocol.GetPTZMaxZoom()));
} else return new WebsocketReply("GET MAX ZOOM", "VapixProtocol not initialized"); } else return new WebsocketReply("GET MAX ZOOM", "VapixProtocol not initialized");
case "GET ZOOM": case "GET ZOOM":
if (vapixProtocol!=null){ if (vapixProtocol!=null){
Blink(LedIpCamera); Blink_LedIpCamera();
return new WebsocketReply("GET ZOOM", String.valueOf(vapixProtocol.GetCurrentZoomValue())); return new WebsocketReply("GET ZOOM", String.valueOf(vapixProtocol.GetCurrentZoomValue()));
} else return new WebsocketReply("GET ZOOM", "VapixProtocol not initialized"); } else return new WebsocketReply("GET ZOOM", "VapixProtocol not initialized");
case "SET ZOOM": case "SET ZOOM":
@@ -424,7 +554,7 @@ public class Main {
if (zoom<vapixProtocol.GetPTZMinZoom()) zoom = vapixProtocol.GetPTZMinZoom(); if (zoom<vapixProtocol.GetPTZMinZoom()) zoom = vapixProtocol.GetPTZMinZoom();
if (zoom>vapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom(); if (zoom>vapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom();
if (vapixProtocol.Zoom(1, zoom)){ if (vapixProtocol.Zoom(1, zoom)){
Blink(LedIpCamera); Blink_LedIpCamera();
return new WebsocketReply("ZOOM", String.valueOf(zoom)); return new WebsocketReply("ZOOM", String.valueOf(zoom));
} else return new WebsocketReply("ZOOM", "Failed to zoom"); } else return new WebsocketReply("ZOOM", "Failed to zoom");
} else return new WebsocketReply("ZOOM", "Invalid Zoom Value"); } else return new WebsocketReply("ZOOM", "Invalid Zoom Value");
@@ -432,15 +562,21 @@ public class Main {
// Live Streaming Related Commands // Live Streaming Related Commands
case "GET BASE64": case "GET BASE64":
if (rtspGrabber!=null){ if (rtspGrabber!=null){
if (Objects.equals(command.data,"HQ")) switch (command.data){
case "HQ":
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus()); return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus());
else case "LQ":
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus()); return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus());
case "YOLO":
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastYoloBase64(), rtspGrabber.HQStreamingStatus());
default:
return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
}
} else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized"); } else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
case "GET RESOLUTION": case "GET RESOLUTION":
if (vapixProtocol!=null){ if (vapixProtocol!=null){
int[] res = vapixProtocol.GetCurrentResolution(1); int[] res = vapixProtocol.GetCurrentResolution(1);
Blink(LedIpCamera); Blink_LedIpCamera();
return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1])); return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1]));
} else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized"); } else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized");
case "GET AUDIOFILES": case "GET AUDIOFILES":