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