Hi Laurent,

> > On Tuesday 12 February 2008, Nathanael Galpin wrote:
> > I've run into an error using the UVC driver with V4L2 to stream data from
> > webcams. Everything works fine the first time around. I allocate buffers,
> > enque them and then stream data from the camera. However, after stopping
> > the camera and unmapping all the buffers, a subsequent attempt to map
> > buffers and start streaming fails.
> 
> That's definitely not how this is supposed to work. Your code is probably 
> missing something.

I've attached a small sample app to the bottom of this email. It's written in
C++ and can be compiled with g++ <filename.cpp>.

> > On a related note, whenever an errenous request is made to the camera, it
> > goes into an error state and won't accept any other commands. Is there a
> > way to clear this error state, or should I just close and reopen the device
> > file?
>
> Which camera are you talking about ? What kind of erroneous request ? Please 
> provide more details along with kernel log messages if available.

I wasn't able to get kernel logging enabled last night for the uvc driver (but I
was pretty tired). I'll spend some more time debugging this and post more 
details
when I have them. I figured I would ask in case there was a generic way to clear
error states in a webcam I wasn't familiar with.

> Best regards,
> Laurent Pinchart

Thanks Laurent,

Nathanael Galpin

Sample App Below

/* Nathanael Galpin 
 *
 * File Name:   testvcamrestart.cpp
 * Description: Tests whether or not streaming data from a camera can be stopped
 *              and started without having to reopen the camera's device file.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>  
#include <vector>
#include <sys/time.h>
#include <iostream>

#include <cstdlib>


#define CLEAR(x) memset (&(x), 0, sizeof (x))
#define PRINTERR(x,y) cout << "ERROR: " << x << " Code: " << y << endl; return y

typedef unsigned int UINT32;

using namespace std;

UINT32 g_xcount;
vector<char *> m_vecpFrameBuffers;
UINT32 m_uiBufferSize;

int xioctl( int fd, int request, void *arg )
{
        g_xcount++;
        int err;
        
        do err = ioctl( fd, request, arg );
        while ( err == -1 && errno == EINTR );
        
        return err;
}

int ReadFrameLoop( int DevHandle )
{
        for ( int i=0; i<10; i++ )
        {
                struct v4l2_buffer buf;
                CLEAR( buf );
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                
                if ( xioctl( DevHandle, VIDIOC_DQBUF, &buf ) )
                {
                        if ( errno != EAGAIN )
                        {
                                PRINTERR( "Failed to Dequeue Buffer", errno );
                        }
                }
                
                cout << "Processing frame: " << buf.sequence << endl;
                
                
                if ( xioctl( DevHandle, VIDIOC_QBUF, &buf ) == -1 )
                { PRINTERR( "Unable to re-enque buffer", errno ); }     
        }
}

int RunCam()
{
        int DevHandle;
        
        cout << "Cam Test Project: Restarting a camera." << endl;
        
        // Open Camera and check capabilities
        struct v4l2_capability cap;
        struct v4l2_requestbuffers req;
        
        if ( (DevHandle = open( "/dev/video0" , O_RDWR, 0 )) == -1 )
        { PRINTERR( "Unable to open device.", errno ); }
        
        if ( xioctl( DevHandle, VIDIOC_QUERYCAP, &cap ) == -1 )
        { PRINTERR( "Not a V4L2 Device.", errno ); }
        
        if ( !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) )
        { PRINTERR( "Not a Video Capture Device.", -1 ); }
        
        if ( !(cap.capabilities & V4L2_CAP_STREAMING) )
        { PRINTERR( "Not capable of streaming video.", -1 ); }
        
        cout << "Video Device Found." << endl;
        
        // Set Video Format
        
        struct v4l2_cropcap cropcap;
        struct v4l2_crop crop;
        struct v4l2_format format;
        
        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if ( ( ioctl( DevHandle, VIDIOC_CROPCAP, &cropcap ) ) == -1 )
        { PRINTERR( "Error Setting CropCap.", errno ); }
        
        // Reset crop to default
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        crop.c = cropcap.defrect;
        if ( ( ioctl( DevHandle, VIDIOC_S_CROP, &crop ) ) == -1 )
        {
                /* EINVAL simply means cropping
                * is not supported.
                */
                if ( errno != EINVAL )   
                { PRINTERR( "Error Setting Crop Area.", errno ); } 
        }
        
        CLEAR( format );
        
        format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        format.fmt.pix.width = 640;
        format.fmt.pix.height = 480;
        format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
        format.fmt.pix.field = V4L2_FIELD_INTERLACED;
        
        if ( ( ioctl( DevHandle, VIDIOC_S_FMT, &format ) ) == -1 )
        { PRINTERR( "Error Setting Video Format.", errno ); }
        
        cout << "Video Device Configured" << endl;
        
        
        
        // Loop to test Camera Restart
        for (UINT32 i=0; i<2; i++)
        {
                // Map Buffers
                CLEAR( req );
                req.count = 4;
                req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                req.memory = V4L2_MEMORY_MMAP;
        
                if ( xioctl( DevHandle, VIDIOC_REQBUFS, &req ) == -1 )
                { PRINTERR( "Memory Mapped I/O not supported.", errno ); }
        
                if ( req.count < 2 )
                { PRINTERR( "Insufficient buffer memory on the device", -1 ); }
        
                m_vecpFrameBuffers.resize( req.count );
        
                for ( UINT32 i=0; i<m_vecpFrameBuffers.size(); i++ )
                {
                        struct v4l2_buffer buf;
        
                        CLEAR( buf );
                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                        buf.memory = V4L2_MEMORY_MMAP;
                        buf.index = i;
        
                        if ( xioctl( DevHandle, VIDIOC_QUERYBUF, &buf ) == -1 )
                        { PRINTERR( "Unable to query buffer.", errno ); }
                        else
                        {
                                m_vecpFrameBuffers[i] = (char *) mmap ( NULL, 
buf.length,
                                                PROT_READ | PROT_WRITE,
                                                MAP_SHARED, DevHandle,
                                                buf.m.offset );
        
        
                                if ( m_vecpFrameBuffers[i] == MAP_FAILED )
                                { PRINTERR( "Mapping buffer failed.", -1 ); }
        
                                m_uiBufferSize = buf.length;
                        }
                }
        
                cout << "Allocated buffers for camera." << endl;
        
                // Enque Buffers
        
                for ( UINT32 i=0; i<m_vecpFrameBuffers.size(); i++ )
                {
                        struct v4l2_buffer buf;
        
                        CLEAR( buf );
                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                        buf.memory = V4L2_MEMORY_MMAP;
                        buf.index = i;
        
                        if ( xioctl( DevHandle, VIDIOC_QBUF, &buf ) == -1 )
                        { 
                                PRINTERR( "Unable to enque buffer.", errno ); 
                                return errno;
                        }
                }
        
                cout << "Buffers enqueued to camera." << endl;
        
                // STREAM ON
        
                enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        
                if ( xioctl( DevHandle, VIDIOC_STREAMON, &type ) != 0 )
                { PRINTERR( "Unable to start camera.", errno ); }
        
                cout << "Streaming data..." << endl;
        
                // Stream some data
        
                ReadFrameLoop( DevHandle );
        
                // STREAM OFF
        
                if ( xioctl( DevHandle, VIDIOC_STREAMOFF, &type ) == -1 )
                { PRINTERR( "Camera may not have shut down cleanly.", errno ); }
        
                cout << "Streaming data stopped." << endl;
        
        
                for ( UINT32 i=0; i<m_vecpFrameBuffers.size(); i++ )
                {
                        if ( munmap( m_vecpFrameBuffers[i], m_uiBufferSize ) == 
-1 )
                        { PRINTERR( "CViperCam: munmap of buffer failed!", 
errno ); }
                }
        
                m_vecpFrameBuffers.clear();
        }
        cout << endl << "Terminated Camera - Code: " << close( DevHandle ) << 
endl;
        return 0;
}

int main(int argc, char *argv[])
{
        RunCam();
        //RunCam();
        
        return EXIT_SUCCESS;
}

_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

Reply via email to