[ipcamera] FFmpeg based alarms will now auto restart if stopped (#13446)

* FFmpeg alarms now auto restart

Signed-off-by: Matthew Skinner <matt@pcmus.com>
This commit is contained in:
Matthew Skinner 2022-10-01 22:19:25 +10:00 committed by GitHub
parent a646fe34e0
commit cc50497f31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 54 deletions

View 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,11 +132,12 @@ public class Ffmpeg {
String line = null;
while ((line = bufferedReader.readLine()) != null) {
logger.debug("{}", line);
if (format.equals(FFmpegFormat.RTSP_ALARMS)) {
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 will take too long to go OFF.
if (countOfMotions < 10) {// Stop increasing otherwise it takes too long to go OFF
countOfMotions++;
}
if (countOfMotions > 9) {
@ -170,6 +172,9 @@ public class Ffmpeg {
} 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;
}

View 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) {

View 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());

View File

@ -1177,6 +1177,8 @@
<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"/>
@ -1727,6 +1729,7 @@
<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"/>