enable better FPS skipping mechanism. For raspberry , optimal at 10 fps.
This commit is contained in:
@@ -59,20 +59,20 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<span class="fa-solid fa-microchip icon-system"></span>
|
<span class="fa-solid fa-microchip icon-system"></span>
|
||||||
<p id="cpu_usage" class="padleft">100 %</p>
|
<p id="cpu_usage" class="padleft">0 %</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<span class="fa-solid fa-temperature-half icon-system"></span>
|
<span class="fa-solid fa-temperature-half icon-system"></span>
|
||||||
<p id="cpu_temperature" class="padleft">55 °C</p>
|
<p id="cpu_temperature" class="padleft">0 °C</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<span class="fa-solid fa-memory icon-system"></span>
|
<span class="fa-solid fa-memory icon-system"></span>
|
||||||
<p id="ram_usage" class="padleft">15 %</p>
|
<p id="ram_usage" class="padleft">0 %</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -12,17 +12,26 @@ import org.bytedeco.javacv.FrameGrabber;
|
|||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
public class GrabbingTask implements Runnable {
|
public class GrabbingTask implements Runnable {
|
||||||
|
// for while loop control
|
||||||
|
private final AtomicBoolean isGrabbing;
|
||||||
|
// for grabbing frames
|
||||||
|
private final FrameGrabber grabber;
|
||||||
|
|
||||||
|
// Consumers
|
||||||
@Setter private Consumer<String> onMessageUpdate;
|
@Setter private Consumer<String> onMessageUpdate;
|
||||||
@Setter private Consumer<Frame> onHQFrameUpdate;
|
@Setter private Consumer<Frame> onHQFrameUpdate;
|
||||||
@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;
|
||||||
|
|
||||||
|
// status of capture fps
|
||||||
@Getter private int CaptureFPS = 0;
|
@Getter private int CaptureFPS = 0;
|
||||||
|
|
||||||
private final AtomicBoolean isGrabbing;
|
@Getter @Setter private int lowquality_width = 640;
|
||||||
private final FrameGrabber grabber;
|
@Getter @Setter private int lowquality_height = 360;
|
||||||
@Getter private final int lowquality_width = 640;
|
|
||||||
@Getter private final int lowquality_height = 360;
|
// for FPS calculation
|
||||||
|
private int intendedFps = 10;
|
||||||
|
|
||||||
private void updateMessage(String message) {
|
private void updateMessage(String message) {
|
||||||
if (onMessageUpdate != null) {
|
if (onMessageUpdate != null) {
|
||||||
@@ -62,10 +71,10 @@ public class GrabbingTask implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber) {
|
public GrabbingTask(AtomicBoolean isGrabbing, FrameGrabber grabber, int fps) {
|
||||||
this.isGrabbing = isGrabbing;
|
this.isGrabbing = isGrabbing;
|
||||||
this.grabber = grabber;
|
this.grabber = grabber;
|
||||||
|
if (fps>0) intendedFps = fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -73,39 +82,51 @@ public class GrabbingTask implements Runnable {
|
|||||||
isGrabbing.set(false);
|
isGrabbing.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void grabprocess() throws Exception{
|
private void processFrame(Frame fr){
|
||||||
grabber.flush();
|
|
||||||
Frame fr =grabber.grab();
|
|
||||||
|
|
||||||
if (fr!=null){
|
if (fr!=null){
|
||||||
updateHQFrame(fr);
|
updateHQFrame(fr);
|
||||||
updateHQBase64(SomeCodes.FrameToBase64(fr));
|
updateHQBase64(SomeCodes.FrameToBase64(fr));
|
||||||
Frame resized = SomeCodes.ResizeFrame(fr, lowquality_width, lowquality_height);
|
Frame resized = SomeCodes.ResizeFrame(fr, lowquality_width, lowquality_height);
|
||||||
updateLQFrame(resized);
|
updateLQFrame(resized);
|
||||||
updateLQBase64(SomeCodes.FrameToBase64(resized));
|
updateLQBase64(SomeCodes.FrameToBase64(resized));
|
||||||
} else updateMessage("Grabber returned null frame");
|
} else updateMessage("processFrame have null frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void flush_grabber(){
|
||||||
|
try {
|
||||||
|
if (grabber!=null) grabber.flush();
|
||||||
|
} catch (FrameGrabber.Exception e) {
|
||||||
|
Logger.error("Error flushing grabber: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
isGrabbing.set(true);
|
isGrabbing.set(true);
|
||||||
Logger.info("Grabbing Task started");
|
Logger.info("Grabbing Task started");
|
||||||
double fps = grabber.getFrameRate();
|
double fps = grabber.getFrameRate();
|
||||||
Logger.info("Grabber framerate = {}", fps);
|
int skippedframes = (int)(fps / intendedFps);
|
||||||
|
//Logger.info("Grabber framerate = {}, intendedFps = {}, Skipping frames = {}", fps, intendedFps, skippedframes);
|
||||||
|
int framecount = 0;
|
||||||
|
flush_grabber();
|
||||||
long starttick = System.currentTimeMillis();
|
long starttick = System.currentTimeMillis();
|
||||||
while (isGrabbing.get()) {
|
while (isGrabbing.get()) {
|
||||||
|
|
||||||
long elapsed = System.currentTimeMillis() - starttick;
|
|
||||||
starttick = System.currentTimeMillis();
|
|
||||||
//Logger.info("Elapsed time = {} ms", elapsed);
|
|
||||||
if (elapsed>0) CaptureFPS = (int) (1000 / elapsed);
|
|
||||||
try{
|
try{
|
||||||
Thread.yield();
|
Thread.yield();
|
||||||
grabprocess();
|
Frame frame = grabber.grab();
|
||||||
|
if (framecount<Integer.MAX_VALUE) framecount++; else framecount = 0;
|
||||||
|
if (framecount % skippedframes == 0) processFrame(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;
|
||||||
|
starttick = System.currentTimeMillis();
|
||||||
|
if (elapsed>0) {
|
||||||
|
int xx = (int) (1000 / elapsed);
|
||||||
|
if (xx<fps) CaptureFPS = xx;
|
||||||
|
}
|
||||||
|
//Logger.info("Elapsed time = {} ms, captureFPS = {}", elapsed, CaptureFPS);
|
||||||
}
|
}
|
||||||
Logger.info("Grabbing Task stopped");
|
Logger.info("Grabbing Task stopped");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ 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.jetbrains.annotations.NotNull;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static Other.SomeCodes.gson;
|
import static Other.SomeCodes.gson;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class RtspGrabber {
|
public class RtspGrabber {
|
||||||
private final String rtspUrl;
|
private final String rtspUrl;
|
||||||
private FFmpegFrameGrabber grabber;
|
private FFmpegFrameGrabber grabber;
|
||||||
@@ -69,40 +71,17 @@ public class RtspGrabber {
|
|||||||
try{
|
try{
|
||||||
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
||||||
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
|
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
|
||||||
grabber.setTimeout(2000);
|
// automatic by RTSP
|
||||||
grabber.setImageWidth(width);
|
//grabber.setImageWidth(width);
|
||||||
grabber.setImageHeight(height);
|
//grabber.setImageHeight(height);
|
||||||
|
//grabber.setTimeout(2000);
|
||||||
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
|
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
|
||||||
grabber.start();
|
grabber.start();
|
||||||
|
|
||||||
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Logger.info("Grabber started");
|
Logger.info("Grabber started");
|
||||||
GrabbingTask tt = new GrabbingTask(isGrabbing, grabber);
|
GrabbingTask tt = getGrabbingTask();
|
||||||
tt.setOnMessageUpdate(Logger::info);
|
|
||||||
tt.setOnHQFrameUpdate(value -> {
|
|
||||||
if (value!=null){
|
|
||||||
if (value.imageWidth>0 && value.imageHeight>0){
|
|
||||||
setLastHQFrame(value);
|
|
||||||
HQWidth = value.imageWidth;
|
|
||||||
HQHeight = value.imageHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tt.setOnLQFrameUpdate(value -> {
|
|
||||||
if (value!=null){
|
|
||||||
if (value.imageWidth>0 && value.imageHeight>0){
|
|
||||||
setLastLQFrame(value);
|
|
||||||
LQWidth = value.imageWidth;
|
|
||||||
LQHeight = value.imageHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tt.setOnHQBase64Update(this::setLastHQBase64);
|
|
||||||
tt.setOnLQBase64Update(this::setLastLQBase64);
|
|
||||||
grabbingTask = tt;
|
grabbingTask = tt;
|
||||||
new Thread(tt).start();
|
new Thread(tt).start();
|
||||||
|
|
||||||
@@ -111,6 +90,8 @@ public class RtspGrabber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop grabbing frames
|
* Stop grabbing frames
|
||||||
*/
|
*/
|
||||||
@@ -139,4 +120,32 @@ public class RtspGrabber {
|
|||||||
public String HQStreamingStatus(){
|
public String HQStreamingStatus(){
|
||||||
return gson.toJson(new String[]{String.valueOf(HQWidth), String.valueOf(HQHeight) , String.valueOf(grabbingTask.getCaptureFPS())});
|
return gson.toJson(new String[]{String.valueOf(HQWidth), String.valueOf(HQHeight) , String.valueOf(grabbingTask.getCaptureFPS())});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private GrabbingTask getGrabbingTask() {
|
||||||
|
GrabbingTask tt = new GrabbingTask(isGrabbing, grabber,10);
|
||||||
|
tt.setOnMessageUpdate(Logger::info);
|
||||||
|
tt.setOnHQFrameUpdate(value -> {
|
||||||
|
if (value!=null){
|
||||||
|
if (value.imageWidth>0 && value.imageHeight>0){
|
||||||
|
setLastHQFrame(value);
|
||||||
|
HQWidth = value.imageWidth;
|
||||||
|
HQHeight = value.imageHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tt.setOnLQFrameUpdate(value -> {
|
||||||
|
if (value!=null){
|
||||||
|
if (value.imageWidth>0 && value.imageHeight>0){
|
||||||
|
setLastLQFrame(value);
|
||||||
|
LQWidth = value.imageWidth;
|
||||||
|
LQHeight = value.imageHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tt.setOnHQBase64Update(this::setLastHQBase64);
|
||||||
|
tt.setOnLQBase64Update(this::setLastLQBase64);
|
||||||
|
return tt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ public class Main {
|
|||||||
init_properties();
|
init_properties();
|
||||||
init_audiofiles();
|
init_audiofiles();
|
||||||
|
|
||||||
|
init_Vapix();
|
||||||
init_audio();
|
init_audio();
|
||||||
|
init_pantiltcontroller();
|
||||||
init_webserver();
|
init_webserver();
|
||||||
init_rtspgrabber();
|
init_rtspgrabber();
|
||||||
init_pantiltcontroller();
|
|
||||||
init_Vapix();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void init_system_monitoring(){
|
private static void init_system_monitoring(){
|
||||||
|
|||||||
Reference in New Issue
Block a user