Fix interlace error on multi-input BT8x8 at large image size

If you've made a patch to quick fix a bug or to add a new feature not yet in the main tree then post it here so others can try it out.
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Fix interlace error on multi-input BT8x8 at large image size

Post by lazyleopard »

ImageImage
This is the hack I made to discard a couple of frames after a camera switch when one BT8x8 chip is being used for multiple cameras at a resolution that means the images are interlaced. I noticed, when using a large image (768x576 PAL) that sometimes the image appeared to have the odd and even half-frames swapped as seen in the first small snippet rather than in the correct order as seen in the second. It seemed to be a side-effect of the switching, so I used this patch to discard a couple of frames after a switch. The end result is that I now always (seem to) be getting good images, though the maximum possible frame rate is reduced significantly (to about 3fps for two cameras on one chip). For me, with clarity and resolution being more important than frame-rate (for now) it's an acceptable compromise, but it wouldn't do for everybody.

Code: Select all

--- zm_local_camera.cpp.orig	Wed Mar 17 10:26:17 2004
+++ zm_local_camera.cpp	Fri Apr 16 12:57:46 2004
@@ -29,6 +29,7 @@
 
 int LocalCamera::camera_count = 0;
 int LocalCamera::m_cap_frame = 0;
+int LocalCamera::m_cap_frame_active = 0;
 int LocalCamera::m_sync_frame = 0;
 video_mbuf LocalCamera::m_vmb;
 video_mmap *LocalCamera::m_vmm;
@@ -80,11 +81,13 @@
 	Debug( 1, ( "Old Y:%d", vid_win.y ));
 	Debug( 1, ( "Old W:%d", vid_win.width ));
 	Debug( 1, ( "Old H:%d", vid_win.height ));
+	Debug(1, ( "Old Fl:%x", vid_win.flags ));
 	
 	vid_win.x = 0;
 	vid_win.y = 0;
 	vid_win.width = width;
 	vid_win.height = height;
+	vid_win.flags = 0;
 
 	if ( ioctl( m_videohandle, VIDIOCSWIN, &vid_win ) < 0 )
 	{
@@ -187,6 +190,7 @@
 	Debug( 1, ( "New Y:%d", vid_win.y ));
 	Debug( 1, ( "New W:%d", vid_win.width ));
 	Debug( 1, ( "New H:%d", vid_win.height ));
+	Debug(1, ( "New Fl:%x", vid_win.flags ));
 	
 	if ( ioctl( m_videohandle, VIDIOCGPICT, &vid_pic) < 0 )
 	{
@@ -530,6 +534,13 @@
 	{
 		//Info(( "Switching" ));
 		struct video_channel vid_src;
+		memset( &vid_src, 0, sizeof(vid_src) );
+		vid_src.channel = channel;
+		if ( ioctl( m_videohandle, VIDIOCGCHAN, &vid_src) < 0 )
+		{
+			Error(( "Failed to get camera source %d: %s", channel, strerror(errno) ));
+			return(-1);
+		}
 
 		vid_src.channel = channel;
 		vid_src.norm = format;
@@ -541,9 +552,10 @@
 			return( -1 );
 		}
 	}
-	if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame] ) < 0 )
+	m_cap_frame_active = m_cap_frame;
+	if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame_active] ) < 0 )
 	{
-		Error(( "Capture failure for frame %d: %s", m_cap_frame, strerror(errno)));
+		Error(( "Capture failure for frame %d: %s", m_cap_frame_active, strerror(errno)));
 		return( -1 );
 	}
 	m_cap_frame = (m_cap_frame+1)%m_vmb.frames;
@@ -553,12 +565,26 @@
 int LocalCamera::PostCapture( Image &image )
 {
 	//Info(( "%s: Capturing image", id ));
-
-	if ( ioctl( m_videohandle, VIDIOCSYNC, &m_sync_frame ) )
+	int lag_reduce = 1;
+	if ( camera_count > 1 ) lag_reduce = 3;
+	while (lag_reduce)
 	{
-		Error(( "Sync failure for frame %d: %s", m_sync_frame, strerror(errno)));
+	    if ( ioctl( m_videohandle, VIDIOCSYNC, &m_sync_frame ) < 0 )
+	    {
+		Error(( "Sync failure for frame %d buffer %d(%d): %s", m_sync_frame, m_cap_frame_active, lag_reduce, strerror(errno)));
 		return( -1 );
 	}
+	    lag_reduce--;
+	    if (lag_reduce)
+	    {
+		if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame_active] ) < 0 )
+		{
+		    Error(( "Capture failure for buffer %d(%d): %s", m_cap_frame_active, lag_reduce, strerror(errno)));
+		    return( -1 );
+		}
+	    }
+	}
+	//Info(( "Captured %d for %d into %d", m_sync_frame, channel, m_cap_frame_active));
 
 	unsigned char *buffer = m_buffer+(m_sync_frame*m_vmb.size/m_vmb.frames);
 	m_sync_frame = (m_sync_frame+1)%m_vmb.frames;
--- zm_local_camera.h.orig	Sun Feb 15 19:53:10 2004
+++ zm_local_camera.h	Wed Apr  7 13:33:56 2004
@@ -39,6 +39,7 @@
 
 protected:
 	static int m_cap_frame;
+	static int m_cap_frame_active;
 	static int m_sync_frame;
 	static video_mbuf m_vmb;
 	static video_mmap *m_vmm;
Last edited by lazyleopard on Wed Jul 07, 2004 5:10 pm, edited 1 time in total.
Rick Hewett
User avatar
zoneminder
Site Admin
Posts: 5215
Joined: Wed Jul 09, 2003 2:07 pm
Location: Bristol, UK
Contact:

Post by zoneminder »

Hi Rick,

I assume this is based on 1.19.1, is that correct?

Phil,
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Post by lazyleopard »

Sorry, realised I'd forgotten to say! Yes, it's based on 1.19.1.

I also notice some tabs have messed the layout a bit. Sorry.

Watch out for the "vid_win.flags = 0;" which helps get rid of the un-wanted error in BT8x8 cards, but which could break things for (IIRC) Phillips cards which use that field for other purposes.
Rick Hewett
malvo
Posts: 6
Joined: Wed Apr 14, 2004 6:38 pm
Location: GER,Brunsvik

Post by malvo »

Is there already a patch for version 1.19.2?
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Post by lazyleopard »

I think the 1.19.1 one works fairly well, but here's my currect diffs:

Code: Select all

--- zm_local_camera.cpp.orig	Mon Apr 19 17:02:17 2004
+++ zm_local_camera.cpp	Fri Apr 23 19:28:21 2004
@@ -29,6 +29,7 @@
 
 int LocalCamera::camera_count = 0;
 int LocalCamera::m_cap_frame = 0;
+int LocalCamera::m_cap_frame_active = 0;
 int LocalCamera::m_sync_frame = 0;
 video_mbuf LocalCamera::m_vmb;
 video_mmap *LocalCamera::m_vmm;
@@ -80,11 +81,13 @@
 	Debug( 1, ( "Old Y:%d", vid_win.y ));
 	Debug( 1, ( "Old W:%d", vid_win.width ));
 	Debug( 1, ( "Old H:%d", vid_win.height ));
+	Debug(1, ( "Old Fl:%x", vid_win.flags ));
 	
 	vid_win.x = 0;
 	vid_win.y = 0;
 	vid_win.width = width;
 	vid_win.height = height;
+	vid_win.flags = 0;
 
 	if ( ioctl( m_videohandle, VIDIOCSWIN, &vid_win ) < 0 )
 	{
@@ -187,6 +190,7 @@
 	Debug( 1, ( "New Y:%d", vid_win.y ));
 	Debug( 1, ( "New W:%d", vid_win.width ));
 	Debug( 1, ( "New H:%d", vid_win.height ));
+	Debug(1, ( "New Fl:%x", vid_win.flags ));
 	
 	if ( ioctl( m_videohandle, VIDIOCGPICT, &vid_pic) < 0 )
 	{
@@ -530,6 +534,13 @@
 	{
 		//Info(( "Switching" ));
 		struct video_channel vid_src;
+		memset( &vid_src, 0, sizeof(vid_src) );
+		vid_src.channel = channel;
+		if ( ioctl( m_videohandle, VIDIOCGCHAN, &vid_src) < 0 )
+		{
+			Error(( "Failed to get camera source %d: %s", channel, strerror(errno) ));
+			return(-1);
+		}
 
 		vid_src.channel = channel;
 		vid_src.norm = format;
@@ -541,9 +552,10 @@
 			return( -1 );
 		}
 	}
-	if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame] ) < 0 )
+	m_cap_frame_active = m_cap_frame;
+	if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame_active] ) < 0 )
 	{
-		Error(( "Capture failure for frame %d: %s", m_cap_frame, strerror(errno)));
+		Error(( "Capture failure for frame %d: %s", m_cap_frame_active, strerror(errno)));
 		return( -1 );
 	}
 	m_cap_frame = (m_cap_frame+1)%m_vmb.frames;
@@ -553,12 +565,26 @@
 int LocalCamera::PostCapture( Image &image )
 {
 	//Info(( "%s: Capturing image", id ));
-
-	if ( ioctl( m_videohandle, VIDIOCSYNC, &m_sync_frame ) )
+	int lag_reduce = 1;
+	if ( camera_count > 1 ) lag_reduce = 3;
+	while (lag_reduce)
 	{
-		Error(( "Sync failure for frame %d: %s", m_sync_frame, strerror(errno)));
+	    if ( ioctl( m_videohandle, VIDIOCSYNC, &m_sync_frame ) < 0 )
+	    {
+		Error(( "Sync failure for frame %d buffer %d(%d): %s", m_sync_frame, m_cap_frame_active, lag_reduce, strerror(errno)));
 		return( -1 );
 	}
+	    lag_reduce--;
+	    if (lag_reduce)
+	    {
+		if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame_active] ) < 0 )
+		{
+		    Error(( "Capture failure for buffer %d(%d): %s", m_cap_frame_active, lag_reduce, strerror(errno)));
+		    return( -1 );
+		}
+	    }
+	}
+	//Info(( "Captured %d for %d into %d", m_sync_frame, channel, m_cap_frame_active));
 
 	unsigned char *buffer = m_buffer+(m_sync_frame*m_vmb.size/m_vmb.frames);
 	m_sync_frame = (m_sync_frame+1)%m_vmb.frames;
Same warnings apply. The vid_win.flags bit may break the handling of Phillips cameras.
Rick Hewett
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Post by lazyleopard »

Yerf! Add:

Code: Select all

--- zm_local_camera.h.orig      Sun Feb 15 19:53:10 2004
+++ zm_local_camera.h   Fri Apr 23 19:28:21 2004
@@ -39,6 +39,7 @@
 
 protected:
        static int m_cap_frame;
+       static int m_cap_frame_active;
        static int m_sync_frame;
        static video_mbuf m_vmb;
        static video_mmap *m_vmm;
This patch (including previous post) can also be applied 1.19.3
Rick Hewett
ada95rules
Posts: 14
Joined: Sun Apr 24, 2005 1:52 am

This is nice

Post by ada95rules »

I was just about to post a question about this. I am having the same field order issue (not simply a time based motion interlace issue) and I was concerned that it was because I did not have my card configured properly.

This looks like it is exactly what I need.

I am upgrading to a 120 fps card to work around this (found one on e-bay..hoping for the best...Really wish I had seen the ad bar on the right of the main page for http://www.bluecherry.net/store/catalog ... views_id=4
before I bid though since now I have to wait and hope to see if the ebay one works out....(I promise I am not a shill for these guys....It just is a bit hard to find a cheap 120 fps card that acknowledges Linux and/or zm support).

In any case, I'll probably end up with more cameras than ports again sometime soon so this should do the trick...Would be nice if this were a device specific option configurable through the zm webpage.

If this patch is installed with a 4 chip card (where the issue would not arrise) will it still impact frame rate?
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Post by lazyleopard »

A 1.21.0 version of this patch follows:

Code: Select all

--- src/zm_local_camera.cpp.orig        2005-02-24 14:40:00.000000000 +0000
+++ src/zm_local_camera.cpp     2005-03-23 13:08:59.000000000 +0000
@@ -29,6 +29,7 @@

 int LocalCamera::camera_count = 0;
 int LocalCamera::m_cap_frame = 0;
+int LocalCamera::m_cap_frame_active = 0;
 int LocalCamera::m_sync_frame = 0;
 video_mbuf LocalCamera::m_vmb;
 video_mmap *LocalCamera::m_vmm;
@@ -543,6 +544,13 @@
        {
                //Info(( "Switching" ));
                struct video_channel vid_src;
+               memset( &vid_src, 0, sizeof(vid_src) );
+               vid_src.channel = channel;
+               if ( ioctl( m_videohandle, VIDIOCGCHAN, &vid_src) < 0 )
+               {
+                       Error(( "Failed to get camera source %d: %s", channel, strerror(errno) ));
+                       return(-1);
+               }

                vid_src.channel = channel;
                vid_src.norm = format;
@@ -554,9 +562,10 @@
                        return( -1 );
                }
        }
-       if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame] ) < 0 )
+       m_cap_frame_active = m_cap_frame;
+       if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame_active] ) < 0 )
        {
-               Error(( "Capture failure for frame %d: %s", m_cap_frame, strerror(errno)));
+               Error(( "Capture failure for frame %d: %s", m_cap_frame_active, strerror(errno)));
                return( -1 );
        }
        m_cap_frame = (m_cap_frame+1)%m_vmb.frames;
@@ -566,12 +575,26 @@
 int LocalCamera::PostCapture( Image &image )
 {
        //Info(( "%s: Capturing image", id ));
-
-       if ( ioctl( m_videohandle, VIDIOCSYNC, &m_sync_frame ) )
-       {
-               Error(( "Sync failure for frame %d: %s", m_sync_frame, strerror(errno)));
+       int lag_reduce = 1;
+       if ( camera_count > 1 ) lag_reduce = 3;
+       while (lag_reduce)
+       {
+           if ( ioctl( m_videohandle, VIDIOCSYNC, &m_sync_frame ) < 0 )
+           {
+               Error(( "Sync failure for frame %d buffer %d(%d): %s", m_sync_frame, m_cap_frame_active, lag_reduce, strerror(errno)));
                return( -1 );
+           }
+           lag_reduce--;
+           if (lag_reduce)
+           {
+               if ( ioctl( m_videohandle, VIDIOCMCAPTURE, &m_vmm[m_cap_frame_active] ) < 0 )
+               {
+                   Error(( "Capture failure for buffer %d(%d): %s", m_cap_frame_active, lag_reduce, strerror(errno)));
+                   return( -1 );
+               }
+           }
        }
+       //Info(( "Captured %d for %d into %d", m_sync_frame, channel, m_cap_frame_active));

        unsigned char *buffer = m_buffer+(m_sync_frame*m_vmb.size/m_vmb.frames);
        m_sync_frame = (m_sync_frame+1)%m_vmb.frames;
--- src/zm_local_camera.h.orig  2005-02-24 14:40:01.000000000 +0000
+++ src/zm_local_camera.h       2005-03-23 13:08:59.000000000 +0000
@@ -39,6 +39,7 @@

 protected:
        static int m_cap_frame;
+       static int m_cap_frame_active;
        static int m_sync_frame;
        static video_mbuf m_vmb;
        static video_mmap *m_vmm;
Rick Hewett
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Re: This is nice

Post by lazyleopard »

ada95rules wrote:If this patch is installed with a 4 chip card (where the issue would not arrise) will it still impact frame rate?
In theory, if there's only 1 camera on a chip the frame-discarding shouldn't happen, but as I've always been running with slowish frame rates and more than one camera, I've never tested it...
Rick Hewett
ada95rules
Posts: 14
Joined: Sun Apr 24, 2005 1:52 am

Post by ada95rules »

I just got my 4 chip card yesterday so once I reconfigure my setup a bit I'll post whether or not there appears to be a slowdown but I can say right now
that with the 2 different cards (one one chip card/four channel card with one camera and one four chip card/eight channel - each with a single camera connected) that the frame dropping does not kick in so it looks like is it operating correctly.

This seems like a pretty decent patch that should be folded into the mainline. I cant imagine anyone wanting those yucky field order frames just to get a few more FPS......but who knows...
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Post by lazyleopard »

Mostly, where FPS matters, folks go for smaller images that don't make use of interlaced frames anyway. Interlacing does unpleasant things to moving targets too, so if you want sharp images of action it also makes sense to use the non-interlaced frame sizes.
Rick Hewett
User avatar
zoneminder
Site Admin
Posts: 5215
Joined: Wed Jul 09, 2003 2:07 pm
Location: Bristol, UK
Contact:

Post by zoneminder »

I'll see if this patch can easily be added in as a configurable option. If so then I'll include it in the next version.

Phil
Ruler
Posts: 235
Joined: Mon Nov 08, 2004 9:02 pm
Location: Bay City, MI

Post by Ruler »

I just found this thread and have a question about the described changes.

I've been getting a lot of false alarms when using motion detection because of the above described interlacing. Does the patch above operate on frames before they get to the analysis daemon? Also, what kind of slowdown should I expect on a single 4-chip bt8x8 card with 8 cameras connected to it? I currently have it set to 2 fps, as the resolution (640x480) is much more important in this application than smooth motion, so limiting the frame rate isn't a problem for me. (The way it stands, the half a terrabyte of drive space only gets me about 2-3 days of footage.)

Also, newbie question, but how do I apply the patch? Phil, you said that you may include this as an option in the next version; any idea if you're going to be including it or when the next version should be ready?
User avatar
lazyleopard
Posts: 403
Joined: Tue Mar 02, 2004 6:12 pm
Location: Gloucestershire, UK

Post by lazyleopard »

Ruler wrote:Does the patch above operate on frames before they get to the analysis daemon?
Yes
Also, what kind of slowdown should I expect on a single 4-chip bt8x8 card with 8 cameras connected to it?
Depends on what you set lag_reduce to. The current setting will discard two frames every time the chip switches camera. In PAL that will cut your maximum total frames per second from 25 to 8. You would seem to have 2 cameras on one chip, so you would get about 4fps on each one. With NTSC it'd be about 5fps.
Also, newbie question, but how do I apply the patch?
Save the code into a file, then use the patch command, probably something like this:

Code: Select all

cd /path/to/zoneminder-1.21.0
patch < /name/of/patch.txt
There's a --dry-run (or --noact, or some such) option on some versions of patch that you can use to see whether it's happy before you actually perform the patch. Check "man patch" for details of the version you have installed.
Rick Hewett
Ruler
Posts: 235
Joined: Mon Nov 08, 2004 9:02 pm
Location: Bay City, MI

Post by Ruler »

Thanks for the info lazy. I did what you said - saved the page as a text file, then edited out all the html around the code segment I needed (1.21.0). I then tried to patch, but when I edited the file, I neglected to undo the word wrapping. I went back in and joined all the lines where appropriate and reran the patch. However, I then got the following errors, none of which I've seen before. Any ideas or hints as to what I'm doing wrong? (I'm on Slackware 10.1 if it matters.)

Code: Select all

root@VSS-Used1:zm-1.21.0-InterlacePatch# patch -p0 < ../zm-1.21.0-interlace.patch
patching file src/zm_local_camera.cpp
Hunk #2 FAILED at 544.
Hunk #3 FAILED at 562.
Hunk #4 FAILED at 575.
3 out of 4 hunks FAILED -- saving rejects to file src/zm_local_camera.cpp.rej
patching file src/zm_local_camera.h
Hunk #1 FAILED at 39.
1 out of 1 hunk FAILED -- saving rejects to file src/zm_local_camera.h.rej

PS - Given the work you must've put into figuring out and implementing this patch, you really shouldn't have an alias of lazy anything. ;)
Post Reply