enable better FPS skipping mechanism. For raspberry , optimal at 10 fps.

This commit is contained in:
2024-11-13 09:29:38 +07:00
parent 068316bb62
commit d2f924f5db
4 changed files with 81 additions and 51 deletions

View File

@@ -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>

View File

@@ -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");
} }

View File

@@ -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;
}
} }

View File

@@ -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(){