Page 1 of 1

Latency Reduction for Remote Cameras

Posted: Sun Sep 30, 2007 6:05 am
by daustin
Hi All,

Here's a simple patch I developed for more reliable streaming
of remote cameras at lower frame rates. The patch actively
drops frames if there are too many buffered up on the
connection.

David

Code: Select all

diff -u -r ./src/zm_remote_camera.cpp ../ZoneMinder-1.22.3.new/src/zm_remote_camera.cpp
--- ./src/zm_remote_camera.cpp  2006-10-19 01:14:10.000000000 +1000
+++ ../ZoneMinder-1.22.3.new/src/zm_remote_camera.cpp   2007-09-30 15:48:13.000000000 +1000
@@ -52,7 +52,7 @@
        request[0] = '\0';
        timeout.tv_sec = 0;
        timeout.tv_usec = 0;
-
+       last_image_size = 0;
        if ( capture )
        {
                Initialise();
@@ -1051,8 +1051,45 @@
        return( 0 );
 }
 
+
+// Patch by David Austin to reduce buffered images for a continuous
+// streamed remote camera.  Especially significant when zoneminder is
+// capturing images at relatively low rates.
+
+int RemoteCamera::ReduceBuffer( int expected_image_size ) {
+       int total_bytes_pending = 0;
+       int content_length;
+
+       if ( expected_image_size == 0 ) {
+               return( 0 );
+       }
+
+       if ( ioctl( sd, FIONREAD, &total_bytes_pending ) < 0 )
+       {
+               Error(( "Can't ioctl(): %s", strerror(errno) ));
+               return( -1 );
+       }
+
+       Debug( 3, ( "Found %d bytes pending", total_bytes_pending));
+
+       if ( total_bytes_pending > 5 * expected_image_size ) {
+               while ( total_bytes_pending > 2.5 * expected_image_size ) {
+                       content_length = GetResponse();
+                       if ( content_length < 0 ) {
+                               return ( -1 );
+                       }
+                       buffer.Consume(content_length);
+                       Debug( 3, ( "Dropping frame of %d bytes", content_length ));
+                       total_bytes_pending -= content_length;
+               }
+       }
+
+       return( 0 );
+}
+
 int RemoteCamera::PreCapture()
 {
+       int do_clear_buffer = true;
        if ( sd < 0 )
        {
                Connect();
@@ -1062,6 +1099,7 @@
                }
                mode = SINGLE_IMAGE;
                buffer.Empty();
+               do_clear_buffer = false;
        }
        if ( mode == SINGLE_IMAGE )
        {
@@ -1070,7 +1108,16 @@
                        Disconnect();
                        return( -1 );
                }
+               do_clear_buffer = false;
        }
+
+       if ( do_clear_buffer ) {
+               if ( ReduceBuffer(last_image_size) < 0 ) {
+                       Disconnect();
+                       return( -1 );
+               }
+       }
+
        return( 0 );
 }
 
@@ -1082,6 +1129,9 @@
                Disconnect();
                return( -1 );
        }
+
+       last_image_size = content_length;
+
        switch( format )
        {
                case JPEG :
diff -u -r ./src/zm_remote_camera.h ../ZoneMinder-1.22.3.new/src/zm_remote_camera.h
--- ./src/zm_remote_camera.h    2006-01-22 04:58:46.000000000 +1100
+++ ../ZoneMinder-1.22.3.new/src/zm_remote_camera.h     2007-09-30 15:46:48.000000000 +1000
@@ -45,6 +45,7 @@
        struct hostent *hp;
        struct sockaddr_in sa;
        int sd;
+       int last_image_size;
        Buffer buffer;
        enum { SINGLE_IMAGE, MULTI_IMAGE } mode;
        enum { UNDEF, JPEG, X_RGB, X_RGBZ } format;
@@ -165,6 +166,7 @@
        int SendRequest();
        int ReadData( Buffer &buffer, int bytes_expected=0 );
        int GetResponse();
+       int ReduceBuffer( int expected_image_size );
        int PreCapture();
        int PostCapture( Image &image );
 };

Posted: Thu Apr 08, 2010 3:57 pm
by jayman
I was wondering where I place this patch.

Posted: Thu Apr 08, 2010 4:04 pm
by jayman
I'm running v1.24.2 BTW

I am just unsure where to put the patch and I am trying to watch camera's over a wan lan extention but they keep going black.