[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux1394-user
Subject:    Re: Camera Capture Flakiness
From:       Johann Schoonees <j.schoonees () irl ! cri ! nz>
Date:       2003-12-07 21:30:39
[Download RAW message or body]

Travis Sparks wrote:
 > Date: Sat, 06 Dec 2003 10:00:30 -0500
 > From: Travis Sparks <sparkst@cs.unc.edu>
 > Reply-To:  sparkst@cs.unc.edu
 > Organization: UNC - Chapel Hill Computer Science
 > To:  linux1394-user@lists.sourceforge.net
 > Subject: Camera Capture Flakiness
 >
 > Our research group at UNC-CH has been fighting firewire camera
 > "flakiness" issues off and on for over a year now with no 
resolution.  I
 > think that our issues are more related to libdc1394, but I cannot rule
 > out libraw.  At this point we would love a solution but are open to
 > ideas on how to better test our setup to ensure things are correct.

Hi Travis

I can unfortunately only give some general pointers.  Someone else may 
be able to pinpoint your problem.

In general, I had to read a lot of source code (libdc1394 and 
video1394) before I got the hang of it.

Be aware that calls to dc1394_dma_multi_capture() block in the 
video1394 driver until a frame is received.  No frame, no return.

There is a bug in the Linux 1394 system (well not so much a bug as an 
incomplete implementation) which causes the camera sometimes to be 
made the cycle master despite its protestations during bus resets that 
it is not cycle master capable.  Nothing you can do about it except 
check that it has happened and trying another reset.  I use code like 
this (hasty cut & paste, not complete but could give you an idea):


typedef struct camera_bus_handle *Cam_handle;
/* This is the camera handle type. */

typedef raw1394handle_t 		 Port_handle;
typedef nodeid_t 			 Node_handle;
typedef struct camera_user_data 	*User_handle;

typedef struct camera_bus_handle
{
     Port_handle port;
     Node_handle node;
     User_handle userdata;
}
camera_bus_handle_struct;

int num_cams = 0;
Cam_handle *handle_array = NULL;

int main(const int argc, const char *argv[])
{
     Cam_handle *handle_array = NULL;
     int retry;
     int bad_bus;
     int num_cameras;

     /* Initialize the camera bus:*/
     handle_array = cambus_create(&num_cameras);
     if (num_cameras < 0 || handle_array == NULL)
     { 	/* Could be the known kernel 1394 cycle master bug. */
	printf("Error initializing the bus: trying reset");
	retry = 3;
	bad_bus = 1;
	while (retry > 0 && bad_bus)
	{
	    printf(" %d", retry);
	    fflush(stdout);
	    cambus_reset();
	    sleep(1);
	    handle_array = cambus_create(&num_cameras);
	    if (num_cameras >= 0 && handle_array != NULL)  bad_bus = 0;
	    retry--;
	}
	if (bad_bus)
	{
	    errorexit(NULL, -1, "Could not initialize the camera bus.");
	}
	else
	{
	    printf("\n\n");
	    fflush(stdout);
	}
     }
     if (num_cameras == 0)
     {
	errorexit(NULL, -1, "Could not find a camera.");
     }
     if (num_cameras == 1)  printf("Found one camera.\n");
     else                   printf("Found %d cameras.\n\n", num_cameras);
     fflush(stdout);

... rest of code in main() ...

}
Cam_handle * cambus_create(int *num_handles)
/* Returns a pointer to an array of all available camera handles.  The
    cameras are not initialized.  The number of handles is returned in
    num_handles.  If no cameras are found, returns a null pointer and 0
    for num_handles.  On error, returns a null pointer and -1 for
    num_handles.  The function cambus_destroy() must be called when done
    to free the allocated memory.  If cambus_create() is called more
    times than cambus_destroy(), then it returns the previous array of
    camera handles and previous number of handles without doing anything
    else. */
{
     int p, n;
     int camcount, num_ports, num_nodes;
     int cycle_master;
     raw1394handle_t p_handle = NULL;
     nodeid_t *nodelist = NULL;

     /* Check whether the bus has not already been created: */
     if (handle_array != NULL && num_cams >= 0)
     {
	*num_handles = num_cams;
	return(handle_array);
     }

     /* Set default (error) values: */
     *num_handles = -1;
     num_cams = 0;

     /* Count the number of visible cameras and IEEE 1394 ports (cards or
        chips): */
     num_ports = count_the_ports();
     if (num_ports < 0)  return(NULL); 	/* Error accessing a port.*/

     camcount = count_the_cameras(num_ports);
     if (camcount < 0)  return(NULL); 	/* Error accessing a port.*/
     if (num_ports == 0)  return(NULL); 	/* Found no ports.*/

     if (camcount == 0) 	/* Nothing wrong, just found no cameras.*/
     {
	*num_handles = 0;
	return(NULL);
     }

     /* Allocate memory for camera handles: */
     handle_array = (Cam_handle *) calloc((size_t) camcount,
					 sizeof(Cam_handle));
     if (handle_array == NULL)  return(NULL); 	/* Allocation failure.*/

     /* Fill in the camera addressing map: */
     for (p = 0; p < num_ports; p++)
     {
	p_handle = dc1394_create_handle(p);
	/*
	if (p_handle == NULL)
	// Internal error: should have been caught in
	// count_the_cameras() above.
	{
	    cambus_destroy();
	    return(NULL);
	}
	*/

         /* Find out who the cycle master is:*/
	cycle_master = raw1394_get_nodecount(p_handle) - 1;
	
	nodelist = dc1394_get_camera_nodes(p_handle, &num_nodes, 0);
	/*
	if ((num_nodes < 0) || ((num_nodes > 0) && (nodelist == NULL)))
	// Internal error: should have been caught in
	// count_the_cameras() above.
	{
	    dc1394_destroy_handle(p_handle);
	    cambus_destroy();
	    return(NULL);
	}
	*/
	for (n = 0; n < num_nodes; n++)
	{
	    if (nodelist[n] == cycle_master)
	    { 	/* Cameras are not cycle master capable. */
		if (n == 0) 	dc1394_destroy_handle(p_handle);
		cambus_destroy();
		return(NULL);
	    }
	    handle_array[num_cams] =
		(Cam_handle) malloc(sizeof(struct camera_bus_handle));
	    if (handle_array[num_cams] == NULL)
	    { 	/* Allocation failure.*/
		if (n == 0) 	dc1394_destroy_handle(p_handle);
		cambus_destroy();
		return(NULL);
	    }
	    handle_array[num_cams]->port = p_handle;
	    handle_array[num_cams]->node = nodelist[n];
	    num_cams++;
	}
	free(nodelist); 	/* Because libdc1394 doesn't.*/
     }

     /* Sanity check: */
     /*
       if (num_cams != camcount) 	// Internal error.
     {
	cambus_destroy();
	return(NULL);
     }
     */

     /* Returns: */
     *num_handles = num_cams;
     return(handle_array);
}

void cambus_reset(void)
/* Requests a reset of each bus which has cameras attached.  All camera
    handles are invalidated.  Any existing handles should first be
    destroyed with cambus_destroy() and re-assigned with cambus_create()
    after the bus reset.  The time needed for a bus reset is
    hardware-dependent and the calling program may have to wait a while
    before trying to access the bus again. */
{
     int num_ports, num_nodes;
     int p, h;
     raw1394handle_t p_handle, last_port = NULL;

     if (handle_array == NULL && num_cams == 0)
     { 	/* No existing bus. */
	num_ports = count_the_ports();
	for (p = 0; p < num_ports; p++)
	{
	    p_handle = dc1394_create_handle(p);
	    if (p_handle)
	    {
		num_nodes = count_the_nodes(p_handle);
		if (num_nodes > 0)  raw1394_reset_bus(p_handle);
		dc1394_destroy_handle(p_handle);
	    }
	}
     }
     else if (handle_array)
     { 	/* A bus exists. */
	for (h = 0; h < num_cams; h++)
	{
	    if ((h == 0) || (handle_array[h]->port != last_port))
	    {
		p_handle = handle_array[h]->port;
		if (p_handle)
		{
		    num_nodes = count_the_nodes(p_handle);
		    if (num_nodes > 0)  raw1394_reset_bus(p_handle);
		    dc1394_destroy_handle(p_handle);
		}
		last_port = p_handle;
	    }
	    free(handle_array[h]);
	}
	free(handle_array);
	handle_array = NULL;
     }
     num_cams = 0;
}


And X should not come into it at all.  I have many times successfully 
run our camera with no X in sight.

Not being able to run again without rebooting is also something I have 
come across.  You will need to tell the video1394 driver to stop 
listening to the channel.  The following code got rid of the need to 
reboot for me:


/*
   Tells the video1394 driver to stop listening to the given channel.
   Compile this file with something like
   gcc -Wall -I../libdc1394-0.9.1/libdc1394 unlisten.c -o unlisten
*/

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "kernel-video1394.h"

#define VIDEO1394_DEVICE_NAME "/dev/video1394/0"

int main(const int argc, const char *argv[])
{
     char *device;
     int fd, channel, retval;

     if (argc < 2)
     {
	fprintf(stderr, "Usage:  %s channel_number\n", argv[0]);
	return(EXIT_FAILURE);
     }
     device = VIDEO1394_DEVICE_NAME;
     fd = open(device, O_RDONLY);
     if (fd < 0)
     {
	fprintf(stderr, "Could not open video1394 device %s\n", device);
	return(EXIT_FAILURE);
     }
     channel = atoi(argv[1]);
     retval = ioctl(fd, VIDEO1394_UNLISTEN_CHANNEL, &channel);
     close(fd);
     return(retval);
}


Do you know about the libdc1394-devel mailing list (also on 
sourceforge) and its archive?  It may be more specific to the kinds of 
problems you decribe.

Regards,
Johann

-- 
^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^
Johann Schoonees                         Imaging & Sensing Team
Industrial Research Limited, PO Box 2225, Auckland, New Zealand
Phone +64 9 9203679 Fax +64 9 3028106 http://www.is.irl.cri.nz/



-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&op=click
_______________________________________________
mailing list Linux1394-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux1394-user
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic