]> git.basschouten.com Git - openhab-addons.git/commitdiff
[ipcamera] FFmpeg based alarms will now auto restart if stopped (#13446)
authorMatthew Skinner <matt@pcmus.com>
Sat, 1 Oct 2022 12:19:25 +0000 (22:19 +1000)
committerGitHub <noreply@github.com>
Sat, 1 Oct 2022 12:19:25 +0000 (14:19 +0200)
* FFmpeg alarms now auto restart

Signed-off-by: Matthew Skinner <matt@pcmus.com>
bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Ffmpeg.java
bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HttpOnlyHandler.java
bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java
bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml

index 2c409827324e55b995ed2f1f60317aadef8e29be..3b3cbacdc0bb68b60f8fa0d6b4e4fbca7b629955 100644 (file)
@@ -54,6 +54,7 @@ public class Ffmpeg {
     private IpCameraFfmpegThread ipCameraFfmpegThread = new IpCameraFfmpegThread();
     private int keepAlive = 8;
     private String password;
+    private Boolean notFrozen = true;
 
     public Ffmpeg(IpCameraHandler handle, FFmpegFormat format, String ffmpegLocation, String inputArguments,
             String input, String outArguments, String output, String username, String password) {
@@ -131,45 +132,49 @@ public class Ffmpeg {
                     String line = null;
                     while ((line = bufferedReader.readLine()) != null) {
                         logger.debug("{}", line);
-                        if (format.equals(FFmpegFormat.RTSP_ALARMS)) {
-                            if (line.contains("lavfi.")) {
-                                // When the number of pixels that change are below the noise floor we need to look
-                                // across frames to confirm it is motion and not noise.
-                                if (countOfMotions < 10) {// Stop increasing otherwise it will take too long to go OFF.
-                                    countOfMotions++;
-                                }
-                                if (countOfMotions > 9) {
-                                    ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
-                                } else if (countOfMotions > 4 && ipCameraHandler.motionThreshold.intValue() > 10) {
-                                    ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
-                                } else if (countOfMotions > 3 && ipCameraHandler.motionThreshold.intValue() > 15) {
-                                    ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
-                                } else if (countOfMotions > 2 && ipCameraHandler.motionThreshold.intValue() > 30) {
-                                    ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
-                                } else if (countOfMotions > 0 && ipCameraHandler.motionThreshold.intValue() > 89) {
-                                    ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
-                                    countOfMotions = 4;// Used to debounce the Alarm.
-                                }
-                            } else if (line.contains("speed=")) {
-                                if (countOfMotions > 0) {
-                                    if (ipCameraHandler.motionThreshold.intValue() > 89) {
-                                        countOfMotions--;
+                        switch (format) {
+                            case RTSP_ALARMS:
+                                if (line.contains("lavfi.")) {
+                                    // When the number of pixels that change are below the noise floor we need to look
+                                    // across frames to confirm it is motion and not noise.
+                                    if (countOfMotions < 10) {// Stop increasing otherwise it takes too long to go OFF
+                                        countOfMotions++;
                                     }
-                                    if (ipCameraHandler.motionThreshold.intValue() > 10) {
-                                        countOfMotions -= 2;
-                                    } else {
-                                        countOfMotions -= 4;
+                                    if (countOfMotions > 9) {
+                                        ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
+                                    } else if (countOfMotions > 4 && ipCameraHandler.motionThreshold.intValue() > 10) {
+                                        ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
+                                    } else if (countOfMotions > 3 && ipCameraHandler.motionThreshold.intValue() > 15) {
+                                        ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
+                                    } else if (countOfMotions > 2 && ipCameraHandler.motionThreshold.intValue() > 30) {
+                                        ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
+                                    } else if (countOfMotions > 0 && ipCameraHandler.motionThreshold.intValue() > 89) {
+                                        ipCameraHandler.motionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
+                                        countOfMotions = 4;// Used to debounce the Alarm.
                                     }
-                                    if (countOfMotions <= 0) {
-                                        ipCameraHandler.noMotionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
-                                        countOfMotions = 0;
+                                } else if (line.contains("speed=")) {
+                                    if (countOfMotions > 0) {
+                                        if (ipCameraHandler.motionThreshold.intValue() > 89) {
+                                            countOfMotions--;
+                                        }
+                                        if (ipCameraHandler.motionThreshold.intValue() > 10) {
+                                            countOfMotions -= 2;
+                                        } else {
+                                            countOfMotions -= 4;
+                                        }
+                                        if (countOfMotions <= 0) {
+                                            ipCameraHandler.noMotionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
+                                            countOfMotions = 0;
+                                        }
                                     }
+                                } else if (line.contains("silence_start")) {
+                                    ipCameraHandler.noAudioDetected();
+                                } else if (line.contains("silence_end")) {
+                                    ipCameraHandler.audioDetected();
                                 }
-                            } else if (line.contains("silence_start")) {
-                                ipCameraHandler.noAudioDetected();
-                            } else if (line.contains("silence_end")) {
-                                ipCameraHandler.audioDetected();
-                            }
+                            case SNAPSHOT:
+                                notFrozen = true;// RTSP_ALARMS and SNAPSHOT both set this to true as there is no break.
+                                break;
                         }
                     }
                 }
@@ -212,7 +217,10 @@ public class Ffmpeg {
     public boolean getIsAlive() {
         Process localProcess = process;
         if (localProcess != null) {
-            return localProcess.isAlive();
+            if (localProcess.isAlive() && notFrozen) {
+                notFrozen = false; // Any process output will set this back to true before next check.
+                return true;
+            }
         }
         return false;
     }
index ac7bc83d9778602b32147946d479a48cf52833a1..6dadb556e780747b8a6510ccb1d431b28590c5fc 100644 (file)
@@ -62,11 +62,11 @@ public class HttpOnlyHandler extends ChannelDuplexHandler {
         switch (channelUID.getId()) {
             case CHANNEL_THRESHOLD_AUDIO_ALARM:
                 if (OnOffType.ON.equals(command)) {
-                    ipCameraHandler.audioAlarmEnabled = true;
+                    ipCameraHandler.ffmpegAudioAlarmEnabled = true;
                 } else if (OnOffType.OFF.equals(command) || DecimalType.ZERO.equals(command)) {
-                    ipCameraHandler.audioAlarmEnabled = false;
+                    ipCameraHandler.ffmpegAudioAlarmEnabled = false;
                 } else {
-                    ipCameraHandler.audioAlarmEnabled = true;
+                    ipCameraHandler.ffmpegAudioAlarmEnabled = true;
                     try {
                         ipCameraHandler.audioThreshold = Integer.valueOf(command.toString());
                     } catch (NumberFormatException e) {
index 500f6e1881c9f02c376bde030734a4d82f9b81e4..08fd5308349329e508ac9717ec5457a4b46e5f15 100644 (file)
@@ -183,8 +183,8 @@ public class IpCameraHandler extends BaseThingHandler {
     public BigDecimal motionThreshold = BigDecimal.ZERO;
     public int audioThreshold = 35;
     public boolean streamingSnapshotMjpeg = false;
-    public boolean motionAlarmEnabled = false;
-    public boolean audioAlarmEnabled = false;
+    public boolean ffmpegMotionAlarmEnabled = false;
+    public boolean ffmpegAudioAlarmEnabled = false;
     public boolean ffmpegSnapshotGeneration = false;
     public boolean snapshotPolling = false;
     public OnvifConnection onvifCamera = new OnvifConnection(this, "", "", "");
@@ -868,20 +868,20 @@ public class IpCameraHandler extends BaseThingHandler {
                 Ffmpeg localAlarms = ffmpegRtspHelper;
                 if (localAlarms != null) {
                     localAlarms.stopConverting();
-                    if (!audioAlarmEnabled && !motionAlarmEnabled) {
+                    if (!ffmpegAudioAlarmEnabled && !ffmpegMotionAlarmEnabled) {
                         return;
                     }
                 }
                 String input = (cameraConfig.getAlarmInputUrl().isEmpty()) ? rtspUri : cameraConfig.getAlarmInputUrl();
                 String filterOptions = "";
-                if (!audioAlarmEnabled) {
+                if (!ffmpegAudioAlarmEnabled) {
                     filterOptions = "-an";
                 } else {
                     filterOptions = "-af silencedetect=n=-" + audioThreshold + "dB:d=2";
                 }
-                if (!motionAlarmEnabled && !ffmpegSnapshotGeneration) {
+                if (!ffmpegMotionAlarmEnabled && !ffmpegSnapshotGeneration) {
                     filterOptions = filterOptions.concat(" -vn");
-                } else if (motionAlarmEnabled && !cameraConfig.getMotionOptions().isEmpty()) {
+                } else if (ffmpegMotionAlarmEnabled && !cameraConfig.getMotionOptions().isEmpty()) {
                     String usersMotionOptions = cameraConfig.getMotionOptions();
                     if (usersMotionOptions.startsWith("-")) {
                         // Need to put the users custom options first in the chain before the motion is detected
@@ -891,7 +891,7 @@ public class IpCameraHandler extends BaseThingHandler {
                         filterOptions = filterOptions + " " + usersMotionOptions + " -vf select='gte(scene,"
                                 + motionThreshold.divide(BIG_DECIMAL_SCALE_MOTION) + ")',metadata=print";
                     }
-                } else if (motionAlarmEnabled) {
+                } else if (ffmpegMotionAlarmEnabled) {
                     filterOptions = filterOptions.concat(" -vf select='gte(scene,"
                             + motionThreshold.divide(BIG_DECIMAL_SCALE_MOTION) + ")',metadata=print");
                 }
@@ -924,9 +924,9 @@ public class IpCameraHandler extends BaseThingHandler {
                 if (ffmpegSnapshot == null) {
                     if (inputOptions.isEmpty()) {
                         // iFrames only
-                        inputOptions = "-threads 1 -skip_frame nokey -hide_banner -loglevel warning";
+                        inputOptions = "-threads 1 -skip_frame nokey -hide_banner";
                     } else {
-                        inputOptions += " -threads 1 -skip_frame nokey -hide_banner -loglevel warning";
+                        inputOptions += " -threads 1 -skip_frame nokey -hide_banner";
                     }
                     ffmpegSnapshot = new Ffmpeg(this, format, cameraConfig.getFfmpegLocation(), inputOptions, rtspUri,
                             cameraConfig.getSnapshotOptions(), "http://127.0.0.1:" + SERVLET_PORT + "/ipcamera/"
@@ -1106,12 +1106,12 @@ public class IpCameraHandler extends BaseThingHandler {
                     return;
                 case CHANNEL_FFMPEG_MOTION_CONTROL:
                     if (OnOffType.ON.equals(command)) {
-                        motionAlarmEnabled = true;
+                        ffmpegMotionAlarmEnabled = true;
                     } else if (OnOffType.OFF.equals(command) || DecimalType.ZERO.equals(command)) {
-                        motionAlarmEnabled = false;
+                        ffmpegMotionAlarmEnabled = false;
                         noMotionDetected(CHANNEL_FFMPEG_MOTION_ALARM);
                     } else if (command instanceof PercentType) {
-                        motionAlarmEnabled = true;
+                        ffmpegMotionAlarmEnabled = true;
                         motionThreshold = ((PercentType) command).toBigDecimal();
                     }
                     setupFfmpegFormat(FFmpegFormat.RTSP_ALARMS);
@@ -1564,9 +1564,15 @@ public class IpCameraHandler extends BaseThingHandler {
                         + cameraConfig.getPassword());
                 break;
         }
-        Ffmpeg localHLS = ffmpegHLS;
-        if (localHLS != null) {
-            localHLS.checkKeepAlive();
+        Ffmpeg localFfmpeg = ffmpegHLS;
+        if (localFfmpeg != null) {
+            localFfmpeg.checkKeepAlive();
+        }
+        if (ffmpegMotionAlarmEnabled || ffmpegAudioAlarmEnabled) {
+            localFfmpeg = ffmpegRtspHelper;
+            if (localFfmpeg == null || !localFfmpeg.getIsAlive()) {
+                setupFfmpegFormat(FFmpegFormat.RTSP_ALARMS);
+            }
         }
         if (openChannels.size() > 10) {
             logger.debug("There are {} open Channels being tracked.", openChannels.size());
index 06ef7a3d89d0d22f36e7a21d40acda19a926ee50..62090a3ff7c6278e5534fdff17cae8baa647c7c5 100644 (file)
                        <channel id="ffmpegMotionAlarm" typeId="ffmpegMotionAlarm"/>
                        <channel id="externalMotion" typeId="externalMotion"/>
                        <channel id="motionAlarm" typeId="motionAlarm"/>
+                       <channel id="thresholdAudioAlarm" typeId="thresholdAudioAlarm"/>
+                       <channel id="audioAlarm" typeId="audioAlarm"/>
                        <channel id="activateAlarmOutput" typeId="activateAlarmOutput"/>
                        <channel id="activateAlarmOutput2" typeId="activateAlarmOutput2"/>
                        <channel id="doorBell" typeId="doorBell"/>
                        <channel id="enableFieldDetectionAlarm" typeId="enableFieldDetectionAlarm"/>
                        <channel id="fieldDetectionAlarm" typeId="fieldDetectionAlarm"/>
                        <channel id="enableAudioAlarm" typeId="enableAudioAlarm"/>
+                       <channel id="thresholdAudioAlarm" typeId="thresholdAudioAlarm"/>
                        <channel id="audioAlarm" typeId="audioAlarm"/>
                        <channel id="activateAlarmOutput" typeId="activateAlarmOutput"/>
                        <channel id="enableExternalAlarmInput" typeId="enableExternalAlarmInput"/>