Skip to content

Commit

Permalink
[ipcamera] Improve ONVIF discovery and bug fixes. (#9199)
Browse files Browse the repository at this point in the history
* Fix Offline detection and Improve discovery.
* Motion options bug fix.
* Message content bug fix.
* Fix all handlers to process all chunks as one.
* Remove password from FFmpeg command log.

Signed-off-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Christian Grasser <info@christiangrasser.at>
  • Loading branch information
Skinah authored and Christian Grasser committed Dec 7, 2020
1 parent fc8b463 commit 67b41f0
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,7 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
}
try {
String content = msg.toString();

if (!content.isEmpty()) {
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
}
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
if (content.contains("Error: No Events")) {
if ("/cgi-bin/eventManager.cgi?action=getEventIndexes&code=VideoMotion".equals(requestUrl)) {
ipCameraHandler.noMotionDetected(CHANNEL_MOTION_ALARM);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,9 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
if (msg == null || ctx == null) {
return;
}
String content = msg.toString();
try {
if (!content.isEmpty()) {
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
}
String content = msg.toString();
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
// determine if the motion detection is turned on or off.
if (content.contains("table.MotionDetect[0].Enable=true")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,9 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
if (msg == null || ctx == null) {
return;
}
String content = msg.toString();
try {
if (!content.isEmpty()) {
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
} else {
return;
}
String content = msg.toString();
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
if (content.contains("doorbell:H")) {
ipCameraHandler.setChannelState(CHANNEL_DOORBELL, OnOffType.ON);
}
Expand All @@ -70,7 +66,6 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
if (content.contains("motionsensor:H")) {
ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
}

} finally {
ReferenceCountUtil.release(msg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ public class Ffmpeg {
private IpCameraFfmpegThread ipCameraFfmpegThread = new IpCameraFfmpegThread();
private int keepAlive = 8;
private boolean running = false;
private String password;

public Ffmpeg(IpCameraHandler handle, FFmpegFormat format, String ffmpegLocation, String inputArguments,
String input, String outArguments, String output, String username, String password) {
this.format = format;
this.password = password;
ipCameraHandler = handle;
String altInput = input;
// Input can be snapshots not just rtsp or http
Expand Down Expand Up @@ -169,7 +171,7 @@ public void run() {
public void startConverting() {
if (!ipCameraFfmpegThread.isAlive()) {
ipCameraFfmpegThread = new IpCameraFfmpegThread();
logger.debug("Starting ffmpeg with this command now:{}", ffmpegCommand);
logger.debug("Starting ffmpeg with this command now:{}", ffmpegCommand.replaceAll(password, "********"));
ipCameraFfmpegThread.start();
running = true;
if (format.equals(FFmpegFormat.HLS)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,9 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
if (msg == null || ctx == null) {
return;
}
String content = msg.toString();
try {
if (!content.isEmpty()) {
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
} else {
return;
}

String content = msg.toString();
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
////////////// Motion Alarm //////////////
if (content.contains("<motionDetectAlarm>")) {
if (content.contains("<motionDetectAlarm>0</motionDetectAlarm>")) {
Expand Down Expand Up @@ -115,7 +110,6 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
ctx.close();
ipCameraHandler.logger.debug("End of FOSCAM handler reached, so closing the channel to the camera now");
}

} finally {
ReferenceCountUtil.release(msg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,10 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
if (msg == null || ctx == null) {
return;
}
String content = "";
int debounce = 3;
try {
content = msg.toString();
if (content.isEmpty()) {
return;
}
int debounce = 3;
String content = msg.toString();
logger.trace("HTTP Result back from camera is \t:{}:", content);

if (content.contains("--boundary")) {// Alarm checking goes in here//
if (content.contains("<EventNotificationAlert version=\"")) {
if (content.contains("hannelID>" + nvrChannel + "</")) {// some camera use c or <dynChannelID>
Expand Down Expand Up @@ -114,7 +109,8 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
countDown();
countDown();
}
} else if (content.contains("<channelID>0</channelID>")) {// NVR uses channel 0 to say all channels
} else if (content.contains("<channelID>0</channelID>")) {// NVR uses channel 0 to say all
// channels
if (content.contains("<eventType>videoloss</eventType>\r\n<eventState>inactive</eventState>")) {
if (vmdCount > 1) {
vmdCount = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,10 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
if (msg == null || ctx == null) {
return;
}
String content = "";
String value1 = "";
try {
content = msg.toString();
if (content.isEmpty()) {
return;
}
String value1 = "";
String content = msg.toString();
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
switch (requestUrl) {
case "/param.cgi?cmd=getinfrared":
if (content.contains("var infraredstat=\"auto")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected void startScan() {
removeOlderResults(getTimestampOfLastScan());
OnvifDiscovery onvifDiscovery = new OnvifDiscovery(this);
try {
onvifDiscovery.discoverCameras(3702);// WS discovery
onvifDiscovery.discoverCameras();
} catch (UnknownHostException | InterruptedException e) {
logger.warn(
"IpCamera Discovery has an issue discovering the network settings to find cameras with. Try setting up the camera manually.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
}
if (contentType.contains("multipart")) {
closeConnection = false;
if (mjpegUri.contains(requestUrl)) {
if (mjpegUri.equals(requestUrl)) {
if (msg instanceof HttpMessage) {
// very start of stream only
ReferenceCountUtil.retain(msg, 1);
Expand All @@ -268,13 +268,13 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
}
}
if (msg instanceof HttpContent) {
if (mjpegUri.contains(requestUrl)) {
if (mjpegUri.equals(requestUrl)) {
// multiple MJPEG stream packets come back as this.
ReferenceCountUtil.retain(msg, 1);
streamToGroup(msg, mjpegChannelGroup, true);
} else {
HttpContent content = (HttpContent) msg;
// Found some cameras uses Content-Type: image/jpg instead of image/jpeg
// Found some cameras use Content-Type: image/jpg instead of image/jpeg
if (contentType.contains("image/jp")) {
for (int i = 0; i < content.content().capacity(); i++) {
incomingJpeg[bytesAlreadyRecieved++] = content.content().getByte(i);
Expand Down Expand Up @@ -304,8 +304,8 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
super.channelRead(ctx, reply);
}
}
// HIKVISION alertStream never has a LastHttpContent as it always stays open//
if (contentType.contains("multipart")) {
// Alarm Streams never have a LastHttpContent as they always stay open//
else if (contentType.contains("multipart")) {
if (bytesAlreadyRecieved != 0) {
reply = incomingMessage;
incomingMessage = "";
Expand All @@ -316,13 +316,14 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
}
// Foscam needs this as will other cameras with chunks//
if (isChunked && bytesAlreadyRecieved != 0) {
logger.debug("Reply is chunked.");
reply = incomingMessage;
super.channelRead(ctx, reply);
}
}
}
} else { // msg is not HttpContent
// Foscam and Amcrest cameras need this
// Foscam cameras need this
if (!contentType.contains("image/jp") && bytesAlreadyRecieved != 0) {
reply = incomingMessage;
logger.debug("Packet back from camera is {}", incomingMessage);
Expand Down Expand Up @@ -982,7 +983,6 @@ public void setupFfmpegFormat(FFmpegFormat format) {
}
}
String input = (cameraConfig.getAlarmInputUrl().isEmpty()) ? rtspUri : cameraConfig.getAlarmInputUrl();
String outputOptions = "-f null -";
String filterOptions = "";
if (!audioAlarmEnabled) {
filterOptions = "-an";
Expand All @@ -991,16 +991,22 @@ public void setupFfmpegFormat(FFmpegFormat format) {
}
if (!motionAlarmEnabled && !ffmpegSnapshotGeneration) {
filterOptions = filterOptions.concat(" -vn");
} else if (motionAlarmEnabled && !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
filterOptions += " " + usersMotionOptions + ",select='gte(scene," + motionThreshold
+ ")',metadata=print";
} else {
filterOptions = filterOptions + " " + usersMotionOptions + " -vf select='gte(scene,"
+ motionThreshold + ")',metadata=print";
}
} else if (motionAlarmEnabled) {
filterOptions = filterOptions
.concat(" -vf select='gte(scene," + motionThreshold + ")',metadata=print");
}
if (!cameraConfig.getUser().isEmpty()) {
filterOptions += " ";// add space as the Framework does not allow spaces at start of config.
}
ffmpegRtspHelper = new Ffmpeg(this, format, cameraConfig.getFfmpegLocation(), inputOptions, input,
filterOptions + cameraConfig.getMotionOptions(), outputOptions, cameraConfig.getUser(),
cameraConfig.getPassword());
filterOptions, "-f null -", cameraConfig.getUser(), cameraConfig.getPassword());
localAlarms = ffmpegRtspHelper;
if (localAlarms != null) {
localAlarms.startConverting();
Expand Down Expand Up @@ -1484,7 +1490,7 @@ public void cameraCommunicationError(String reason) {
boolean streamIsStopped(String url) {
ChannelTracking channelTracking = channelTrackingMap.get(url);
if (channelTracking != null) {
if (channelTracking.getChannel().isOpen()) {
if (channelTracking.getChannel().isActive()) {
return false; // stream is running.
}
}
Expand Down Expand Up @@ -1534,20 +1540,21 @@ public void startSnapshotPolling() {
}
}

// runs every 8 seconds due to mjpeg streams not staying open unless they update this often.
/**
* {@link pollCameraRunnable} Polls every 8 seconds, to check camera is still ONLINE and keep mjpeg and alarm
* streams open and more.
*
*/
void pollCameraRunnable() {
// Snapshot should be first to keep consistent time between shots
if (!snapshotUri.isEmpty()) {
if (updateImageChannel) {
sendHttpGET(snapshotUri);
}
}
if (streamingAutoFps) {
updateAutoFps = true;
if (!snapshotPolling && !ffmpegSnapshotGeneration) {
// Dont need to poll if creating from RTSP stream with FFmpeg or we are polling at full rate already.
sendHttpGET(snapshotUri);
}
} else if (!snapshotUri.isEmpty() && !snapshotPolling) {// we need to check camera is still online.
sendHttpGET(snapshotUri);
}
// NOTE: Use lowPriorityRequests if get request is not needed every poll.
if (!lowPriorityRequests.isEmpty()) {
Expand Down
Loading

0 comments on commit 67b41f0

Please sign in to comment.