40 #include <sys/ioctl.h>
43 #include <linux/videodev2.h>
46 #if GCONFIG_HAVE_LIBV4L
48 namespace {
bool have_libv4l() {
return true ; } }
52 bool have_libv4l() {
return false ; }
53 int v4l2_open(
const char * p ,
int n , mode_t m ) { return ::open( p , n , m ) ; }
54 void v4l2_close(
int fd ) { ::close( fd ) ; }
55 void * v4l2_mmap(
void * p ,
size_t n ,
int prot ,
int flags ,
int fd , off_t o ) { return ::mmap( p , n , prot , flags , fd , o ) ; }
56 int v4l2_munmap(
void * p ,
size_t n ) { return ::munmap( p , n ) ; }
57 int v4l2_read(
int fd ,
void * p ,
size_t n ) { return ::read( fd , p , n ) ; }
58 int v4l2_ioctl(
int fd ,
int request ,
void * arg ) { return ::ioctl( fd , request , arg ) ; }
64 struct ioctl_name {
unsigned int n ;
const char * p ; } ioctl_names[] = {
65 { VIDIOC_CROPCAP ,
"VIDIOC_CROPCAP" } ,
66 { VIDIOC_DQBUF ,
"VIDIOC_DQBUF" } ,
67 { VIDIOC_G_SELECTION ,
"VIDIOC_G_SELECTION" } ,
68 { VIDIOC_QBUF ,
"VIDIOC_QBUF" } ,
69 { VIDIOC_QUERYBUF ,
"VIDIOC_QUERYBUF" } ,
70 { VIDIOC_QUERYCAP ,
"VIDIOC_QUERYCAP" } ,
71 { VIDIOC_REQBUFS ,
"VIDIOC_REQBUFS" } ,
72 { VIDIOC_S_CROP ,
"VIDIOC_S_CROP" } ,
73 { VIDIOC_S_FMT ,
"VIDIOC_S_FMT" } ,
74 { VIDIOC_TRY_FMT ,
"VIDIOC_TRY_FMT" } ,
75 { VIDIOC_S_INPUT ,
"VIDIOC_S_INPUT" } ,
76 { VIDIOC_S_SELECTION ,
"VIDIOC_S_SELECTION" } ,
77 { VIDIOC_STREAMOFF ,
"VIDIOC_STREAMOFF" } ,
78 { VIDIOC_STREAMON ,
"VIDIOC_STREAMON" } ,
79 { VIDIOC_ENUM_FMT ,
"VIDIOC_ENUM_FMT" } ,
83 std::string fourcc( g_uint32_t pf )
86 result.append( 1U ,
char((pf>>0)&0xff) ) ;
87 result.append( 1U ,
char((pf>>8)&0xff) ) ;
88 result.append( 1U ,
char((pf>>16)&0xff) ) ;
89 result.append( 1U ,
char((pf>>24)&0xff) ) ;
105 typedef std::pair<int,int> pair_t ;
106 static bool set_format( v4l2_format * ,
int fd ,
unsigned int dx ,
unsigned int dy , g_uint32_t pf ,
107 g_uint32_t f ,
const char * pfn ,
const char * fn ) ;
108 static bool set_format( v4l2_format * ,
int fd ,
unsigned int dx ,
unsigned int dy , g_uint32_t pf ,
110 static pair_t xioctl(
int fd ,
int request ,
void * arg ,
bool v ) ;
111 static bool xioctl_ok(
int fd ,
int request ,
void * arg ,
bool v =
false ) ;
112 static void xioctl_warn(
int fd ,
int request ,
void * arg ,
bool v =
false ) ;
113 static void xioctl_check(
int fd ,
int request ,
void * arg ,
bool v =
false ) ;
114 static bool xioctl_eagain(
int fd ,
int request ,
void * arg ,
bool v =
false ) ;
115 static void xioctl_einval(
int fd ,
int request ,
void * arg ,
const std::string & more ,
bool v =
false ) ;
116 static const char * xioctl_name (
int request ) ;
117 static void throw_errno(
const char * ,
int e ) ;
119 static bool m_use_libv4l ;
120 static int xioctl_imp(
int fd ,
int request ,
void * arg ) ;
121 static int open(
const char * ,
int , mode_t ) ;
122 static void close(
int ) ;
123 static void * mmap(
void * ,
size_t ,
int ,
int ,
int fd , off_t ) ;
124 static int read(
int ,
void * ,
size_t ) ;
129 typedef std::vector<int> List ;
130 static List m_list_lib ;
131 static List m_list_raw ;
133 static void add(
int ,
bool ) ;
134 static void remove(
int fd ) ;
144 typedef struct v4l2_buffer buffer_type ;
146 buffer_type & m_buffer ;
155 m_io(IO_METHOD_MMAP) ,
162 CaptureImp::m_use_libv4l = have_libv4l() ;
164 CaptureImp::m_use_libv4l = false ;
166 static bool first = true ;
170 G_LOG(
"Gv::CaptureV4l::ctor: libv4l is " << (have_libv4l()?
"":
"not ") <<
"built-in"
171 << ((have_libv4l()&&!CaptureImp::m_use_libv4l)?
" but disabled by 'nolibv4l' device option":
"") ) ;
174 m_fd = open_device( dev_name ) ;
175 m_io = check_device( m_fd , dev_config ) ;
176 m_buffer_scale = init_device( dev_config ) ;
177 create_buffers( m_buffer_scale.m_buffersize , dev_config ) ;
180 set_simple( dev_config ) ;
181 G_ASSERT( m_dx > 0 && m_dy > 0 ) ;
187 CaptureImp::close( m_fd ) ;
212 std::ostringstream ss ;
214 <<
"io=" << (m_simple?
"simple-":
"") << (m_io==IO_METHOD_READ?
"read":(m_io==IO_METHOD_MMAP?
"mmap":
"userptr")) <<
" "
215 <<
"dx=" << m_dx <<
" dy=" << m_dy <<
" "
216 <<
"format=[" << m_format.name() <<
"] "
217 <<
"fourcc=[" << fourcc(m_format.id()) <<
"]" ;
221 void Gv::CaptureV4l::set_simple(
const std::string & dev_config )
224 m_io == IO_METHOD_READ &&
225 m_format.is_simple() &&
226 m_buffer_scale.m_buffersize == size_t(m_dx)*size_t(m_dy)*size_t(3U) &&
227 dev_config.find(
"nosimple") == std::string::npos ;
237 G_ASSERT( m_io == IO_METHOD_READ ) ;
238 if( m_io != IO_METHOD_READ )
return false ;
239 return read_frame_read_simple( p , n ) ;
244 if( m_io == IO_METHOD_READ )
246 if( !read_frame_read(callback) )
249 else if( m_io == IO_METHOD_MMAP )
251 if( !read_frame_mmap(callback) )
256 if( !read_frame_userptr(callback) )
262 bool Gv::CaptureV4l::read_frame_read_simple(
unsigned char * p ,
size_t n )
264 G_ASSERT( p !=
nullptr && n > 0U ) ;
265 ssize_t rc = CaptureImp::read( m_fd , p , n ) ;
269 if( e == EAGAIN )
return false ;
270 CaptureImp::throw_errno(
"read" , e ) ;
275 bool Gv::CaptureV4l::read_frame_read( CaptureCallback & callback )
277 G_ASSERT( m_buffers.size() <= 1U ) ;
278 G_ASSERT( m_buffer_scale.m_buffersize > 0U ) ;
279 if( m_buffers.empty() )
280 m_buffers.push_back( shared_ptr<CaptureBuffer>(
new CaptureBuffer(m_buffer_scale.m_buffersize)) ) ;
282 ssize_t rc = CaptureImp::read( m_fd , m_buffers[0]->begin() , m_buffers[0]->size() ) ;
286 if( e == EAGAIN )
return false ;
287 CaptureImp::throw_errno(
"read" , e ) ;
290 buffer.
setFormat( m_format , m_buffer_scale ) ;
295 bool Gv::CaptureV4l::read_frame_mmap( CaptureCallback & callback )
298 static struct v4l2_buffer zero_buf ;
299 struct v4l2_buffer buf = zero_buf ;
300 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
301 buf.memory = V4L2_MEMORY_MMAP ;
302 if( CaptureImp::xioctl_eagain( m_fd , VIDIOC_DQBUF , &buf ) )
306 CaptureRequeuer requeuer( m_fd , buf ) ;
308 G_ASSERT( m_buffers.size() >= 1U ) ;
309 G_ASSERT( buf.index < m_buffers.size() ) ;
311 buffer.
setFormat( m_format , m_buffer_scale ) ;
316 bool Gv::CaptureV4l::read_frame_userptr( CaptureCallback & callback )
319 static struct v4l2_buffer zero_buf ;
320 static struct v4l2_buffer buf = zero_buf ;
321 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
322 buf.memory = V4L2_MEMORY_USERPTR ;
323 if( CaptureImp::xioctl_eagain( m_fd , VIDIOC_DQBUF, &buf ) )
327 CaptureRequeuer requeuer( m_fd , buf ) ;
330 G_ASSERT( m_buffers.size() >= 1U ) ;
332 for( ; i < m_buffers.size() ; ++i )
334 if( buf.m.userptr == reinterpret_cast<unsigned long>(m_buffers[i]->begin()) &&
335 buf.length == m_buffers[i]->size() )
338 if( i >= m_buffers.size() )
339 throw Capture::Error(
"buffer not found" ) ;
342 buffer.
setFormat( m_format , m_buffer_scale ) ;
351 if( m_io == IO_METHOD_READ )
352 stop_capturing_read() ;
353 else if( m_io == IO_METHOD_MMAP )
354 stop_capturing_mmap( m_fd ) ;
356 stop_capturing_userptr( m_fd ) ;
361 void Gv::CaptureV4l::stop_capturing_read()
366 void Gv::CaptureV4l::stop_capturing_mmap(
int fd )
368 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
369 CaptureImp::xioctl_warn( fd , VIDIOC_STREAMOFF , &type ) ;
372 void Gv::CaptureV4l::stop_capturing_userptr(
int fd )
374 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
375 CaptureImp::xioctl_warn( fd , VIDIOC_STREAMOFF , &type ) ;
378 void Gv::CaptureV4l::add_buffers()
380 if( m_io == IO_METHOD_READ )
382 else if( m_io == IO_METHOD_MMAP )
383 add_buffers_mmap( m_buffers , m_fd ) ;
385 add_buffers_userptr( m_buffers , m_fd ) ;
388 void Gv::CaptureV4l::add_buffers_read()
393 void Gv::CaptureV4l::add_buffers_mmap( CaptureBuffers & buffers ,
int fd )
395 G_ASSERT( buffers.size() > 0U ) ;
396 for(
unsigned int i = 0 ; i < buffers.size() ; ++i )
398 static struct v4l2_buffer zero_buf ;
399 struct v4l2_buffer buf = zero_buf ;
400 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
401 buf.memory= V4L2_MEMORY_MMAP ;
404 CaptureImp::xioctl_check( fd , VIDIOC_QBUF , &buf ) ;
408 void Gv::CaptureV4l::add_buffers_userptr( CaptureBuffers & buffers ,
int fd )
410 G_ASSERT( buffers.size() > 0U ) ;
411 for(
unsigned int i = 0 ; i < buffers.size() ; ++i )
413 static struct v4l2_buffer zero_buf ;
414 struct v4l2_buffer buf = zero_buf ;
415 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
416 buf.memory= V4L2_MEMORY_USERPTR ;
418 buf.m.userptr =
reinterpret_cast<unsigned long>( buffers[i]->begin() ) ;
419 buf.length = buffers[i]->size() ;
421 CaptureImp::xioctl_check( fd , VIDIOC_QBUF , &buf ) ;
429 if( m_io == IO_METHOD_READ )
430 start_capturing_read() ;
431 else if( m_io == IO_METHOD_MMAP )
432 start_capturing_mmap( m_fd ) ;
434 start_capturing_userptr( m_fd ) ;
439 void Gv::CaptureV4l::start_capturing_read()
444 void Gv::CaptureV4l::start_capturing_mmap(
int fd )
446 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
447 CaptureImp::xioctl_check( fd , VIDIOC_STREAMON , &type ) ;
450 void Gv::CaptureV4l::start_capturing_userptr(
int fd )
452 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
453 CaptureImp::xioctl_check( fd , VIDIOC_STREAMON , &type ) ;
456 void Gv::CaptureV4l::create_buffers( size_type buffersize ,
const std::string & dev_config )
460 if( m_io == IO_METHOD_READ )
461 create_buffers_read( m_buffers , buffersize , nbuffers ) ;
462 else if( m_io == IO_METHOD_MMAP )
463 create_buffers_mmap( m_buffers , m_fd , buffersize , nbuffers == 0U ? 2U : nbuffers ) ;
465 create_buffers_userptr( m_buffers , m_fd , buffersize , nbuffers == 0U ? 4U : nbuffers ) ;
468 void Gv::CaptureV4l::create_buffers_read( CaptureBuffers & buffers , size_type buffer_size ,
unsigned int nbuffers )
470 G_LOG(
"Gv::CaptureV4l::create_buffers_read: read buffers: request=" << nbuffers <<
" count=1 size=" << buffer_size ) ;
474 void Gv::CaptureV4l::create_buffers_mmap( CaptureBuffers & buffers ,
int fd ,
size_t buffersize ,
unsigned int nbuffers )
477 static struct v4l2_requestbuffers zero_req ;
478 struct v4l2_requestbuffers req = zero_req ;
479 req.count = nbuffers ;
480 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
481 req.memory = V4L2_MEMORY_MMAP ;
482 CaptureImp::xioctl_einval( fd , VIDIOC_REQBUFS , &req ,
"device does not support memory mapped streaming" ) ;
484 throw Capture::Error(
"insufficient buffer memory" ) ;
487 for(
unsigned int i = 0 ; i < req.count ; ++i )
490 static struct v4l2_buffer zero_buf ;
491 struct v4l2_buffer buf = zero_buf ;
492 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
493 buf.memory = V4L2_MEMORY_MMAP ;
495 CaptureImp::xioctl_check( fd , VIDIOC_QUERYBUF , &buf ) ;
498 G_LOG(
"Gv::CaptureV4l::create_buffers_mmap: mmap buffers: request=" << nbuffers <<
" count=" << req.count <<
" size=" << buf.length ) ;
500 if( buf.length < buffersize )
501 throw Capture::Error(
"buffer size mis-match between VIDIOC_QUERYBUF and VIDIOC_S_FMT" ) ;
503 void * p = CaptureImp::mmap(
nullptr , buf.length , PROT_READ | PROT_WRITE , MAP_SHARED , fd , buf.m.offset ) ;
504 if( p == MAP_FAILED )
507 CaptureImp::throw_errno(
"mmap" , e ) ;
510 buffers.push_back( shared_ptr<CaptureBuffer>(
new CaptureBuffer(buf.length,p,::v4l2_munmap) ) ) ;
512 G_ASSERT( !buffers.empty() ) ;
515 void Gv::CaptureV4l::create_buffers_userptr( CaptureBuffers & buffers ,
int fd , size_type buffersize_in ,
unsigned int nbuffers )
517 const int page_size = getpagesize() ;
519 throw Capture::Error(
"assertion failure: invalid pagesize" ) ;
521 unsigned int page =
static_cast<unsigned int>(page_size) ;
522 size_t buffersize = (buffersize_in + page - 1U) & ~(page - 1U) ;
523 G_ASSERT( buffersize >= buffersize_in ) ;
525 static struct v4l2_requestbuffers zero_req ;
526 struct v4l2_requestbuffers req = zero_req ;
527 req.count = nbuffers ;
528 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
529 req.memory = V4L2_MEMORY_USERPTR ;
530 CaptureImp::xioctl_einval( fd , VIDIOC_REQBUFS, &req ,
"device does not support user pointer i/o" ) ;
533 throw Capture::Error(
"invalid negotiated buffer count" ) ;
535 G_LOG(
"Gv::CaptureV4l::create_buffers_userptr: userptr buffers: request=" << nbuffers <<
" count=" << req.count <<
" size=" << buffersize ) ;
537 for(
unsigned int i = 0U ; i < req.count ; ++i )
539 buffers.push_back( shared_ptr<CaptureBuffer>(
new CaptureBuffer(page_size,buffersize) ) ) ;
541 G_ASSERT( !buffers.empty() ) ;
544 int Gv::CaptureV4l::open_device(
const std::string & dev_name )
547 int rc = stat( dev_name.c_str() , &st ) ;
550 std::string help( G::is_linux() ?
" or do \"modprobe vivi\" as root" :
"" ) ;
551 throw Capture::NoDevice(
"[" + dev_name +
"]: try device \"test\"" + help ) ;
554 if( !S_ISCHR(st.st_mode) )
555 throw Capture::Error(
"not a device: " + dev_name ) ;
557 int fd = CaptureImp::open( dev_name.c_str() , O_RDWR | O_NONBLOCK , 0 ) ;
559 throw Capture::Error(
"cannot open [" + dev_name +
"]: " + G::Process::strerror(errno) ) ;
561 ::fcntl( fd , F_SETFD , ::fcntl(fd,F_GETFD) | FD_CLOEXEC ) ;
571 struct v4l2_capability cap ;
572 CaptureImp::xioctl_einval( fd , VIDIOC_QUERYCAP, &cap ,
"device is not a V4L2 device" ) ;
573 if( !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) )
574 throw Capture::Error(
"device is not a video capture device" ) ;
576 const bool can_read = !! (cap.capabilities & V4L2_CAP_READWRITE) ;
577 const bool can_stream = !! (cap.capabilities & V4L2_CAP_STREAMING) ;
578 G_LOG(
"Gv::CaptureV4l::check_device: device capabilities: can-read=" << can_read <<
" can-stream=" << can_stream ) ;
580 const char * error = nullptr ;
581 if( !can_read && !can_stream )
582 error =
"device does not support any i/o method" ;
584 if( config_read && !can_read )
585 error =
"device does not support read i/o" ;
587 if( ( config_userptr || config_mmap ) && !can_stream )
588 error =
"device does not support streaming i/o" ;
597 CaptureImp::m_use_libv4l ?
598 ( can_read ? IO_METHOD_READ : IO_METHOD_MMAP ) :
599 ( can_stream ? IO_METHOD_MMAP : IO_METHOD_READ ) ;
601 if( config_read ) method = IO_METHOD_READ ;
602 if( config_mmap ) method = IO_METHOD_MMAP ;
603 if( config_userptr ) method = IO_METHOD_USERPTR ;
605 G_LOG(
"Gv::CaptureV4l::check_device: device io-method: "
606 <<
"require-mmap=" << config_mmap <<
" "
607 <<
"require-read=" << config_read <<
" "
608 <<
"require-userptr=" << config_userptr <<
" "
609 <<
"can-read=" << can_read <<
" "
610 <<
"can-stream=" << can_stream <<
": "
611 << (error?error:(method==IO_METHOD_READ?
"read":(method==IO_METHOD_MMAP?
"mmap":
"userptr")))
614 if( error !=
nullptr )
615 throw Capture::Error( error ) ;
628 if( f.
is_rgb() )
return 0 ;
629 if( f.
is_yuv() )
return 1 ;
635 return d == 8 ? -1000 : -d ;
643 if( format_type_gross(a) != format_type_gross(b) )
return format_type_gross(a) < format_type_gross(b) ;
644 if( format_depth(a) != format_depth(b) )
return format_depth(a) < format_depth(b) ;
645 if( format_type_fine(a) != format_type_fine(b) )
return format_type_fine(a) < format_type_fine(b) ;
646 if( format_compression(a) != format_compression(b) )
return format_compression(a) < format_compression(b) ;
656 CaptureImp::xioctl_warn( m_fd , VIDIOC_S_INPUT , &index ,
true ) ;
662 unsigned int dx = 0 ;
663 unsigned int dy = 0 ;
667 static struct v4l2_cropcap zero_cropcap ;
668 struct v4l2_cropcap cropcap = zero_cropcap ;
669 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
670 struct v4l2_crop crop ;
671 if( CaptureImp::xioctl_ok( m_fd , VIDIOC_CROPCAP , &cropcap ,
true ) )
673 dx = cropcap.defrect.width ;
674 dy = cropcap.defrect.height ;
676 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
677 crop.c = cropcap.defrect;
678 done = CaptureImp::xioctl_ok( m_fd , VIDIOC_S_CROP , &crop ,
true ) ;
683 static struct v4l2_selection zero_selection ;
684 struct v4l2_selection selection = zero_selection ;
685 selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
686 selection.target = V4L2_SEL_TGT_CROP_DEFAULT ;
687 if( CaptureImp::xioctl_ok( m_fd , VIDIOC_G_SELECTION , &selection ,
true ) )
689 dx = selection.r.width ;
690 dy = selection.r.height ;
692 selection.target = V4L2_SEL_TGT_CROP ;
693 done = CaptureImp::xioctl_ok( m_fd , VIDIOC_S_SELECTION , &selection ,
true ) ;
700 const int sanity = 1000 ;
701 for(
int i = 0 ; i < sanity ; i++ )
703 static struct v4l2_fmtdesc zero_fmtdesc ;
704 struct v4l2_fmtdesc fmtdesc = zero_fmtdesc ;
707 if( ! CaptureImp::xioctl_ok( m_fd , VIDIOC_ENUM_FMT , &fmtdesc ,
true ) )
710 if( fmtdesc.type != V4L2_BUF_TYPE_VIDEO_CAPTURE )
713 const char * description =
reinterpret_cast<char *
>(fmtdesc.description) ;
714 fmtdesc.description[
sizeof(fmtdesc.description)-1] =
'\0' ;
716 G_LOG(
"Gv::CaptureV4l::init_device: device format " << i <<
": "
717 <<
"pixelformat=" << fmtdesc.pixelformat <<
" "
718 <<
"fourcc=[" << fourcc(fmtdesc.pixelformat) <<
"] "
720 <<
"flags=" << fmtdesc.flags ) ;
729 std::vector<CaptureBufferFormat> format ;
731 typedef CaptureBufferFormat Format ;
732 typedef CaptureBufferFormat::Type Type ;
733 typedef CaptureBufferComponent Component ;
734 const CaptureBufferComponent::Type c_byte = CaptureBufferComponent::c_byte ;
735 const CaptureBufferComponent::Type c_word_le = CaptureBufferComponent::c_word_le ;
736 const CaptureBufferComponent::Type c_word_be = CaptureBufferComponent::c_word_be ;
737 const size_t XY = Gv::CaptureBufferComponent::XY ;
738 const size_t XY2 = Gv::CaptureBufferComponent::XY2 ;
739 const size_t XY4 = Gv::CaptureBufferComponent::XY4 ;
740 const size_t XY8 = Gv::CaptureBufferComponent::XY8 ;
742 static const Format ff[] = {
743 Format( V4L2_PIX_FMT_RGB332 ,
"rgb332" ,
Format::rgb ,
745 Component( 0 , 0 , 0 , 1 , 3 , 5 , c_byte ) ,
746 Component( 0 , 0 , 0 , 1 , 3 , 2 , c_byte ) ,
747 Component( 0 , 0 , 0 , 1 , 2 , 0 , c_byte ) ) ,
748 Format( V4L2_PIX_FMT_RGB565X ,
"rgb565x" ,
Format::rgb ,
749 Component( 0 , 0 , 0 , 2 , 5 , 11 , c_word_be ) ,
750 Component( 0 , 0 , 0 , 2 , 6 , 5 , c_word_be ) ,
751 Component( 0 , 0 , 0 , 2 , 5 , 0 , c_word_be ) ) ,
752 Format( V4L2_PIX_FMT_RGB24 ,
"rgb24" ,
Format::rgb ,
753 Component( 0 , 0 , 0 , 3 , 8 , 0 , c_byte ) ,
754 Component( 1 , 0 , 0 , 3 , 8 , 0 , c_byte ) ,
755 Component( 2 , 0 , 0 , 3 , 8 , 0 , c_byte ) ) ,
756 Format( V4L2_PIX_FMT_BGR24 ,
"bgr24" ,
Format::rgb ,
757 Component( 2 , 0 , 0 , 3 , 8 , 0 , c_byte ) ,
758 Component( 1 , 0 , 0 , 3 , 8 , 0 , c_byte ) ,
759 Component( 0 , 0 , 0 , 3 , 8 , 0 , c_byte ) ) ,
760 Format( V4L2_PIX_FMT_RGB444 ,
"rgb444" ,
Format::rgb ,
761 Component( 0 , 0 , 0 , 2 , 4 , 8 , c_word_le ) ,
762 Component( 0 , 0 , 0 , 2 , 4 , 4 , c_word_le ) ,
763 Component( 0 , 0 , 0 , 2 , 4 , 0 , c_word_le ) ) ,
764 Format( V4L2_PIX_FMT_RGB555 ,
"rgb555" ,
Format::rgb ,
765 Component( 0 , 0 , 0 , 2 , 5 , 10 , c_word_le ) ,
766 Component( 0 , 0 , 0 , 2 , 5 , 5 , c_word_le ) ,
767 Component( 0 , 0 , 0 , 2 , 5 , 0 , c_word_le ) ) ,
768 Format( V4L2_PIX_FMT_RGB555X ,
"rgb555x" ,
Format::rgb ,
769 Component( 0 , 0 , 0 , 2 , 5 , 10 , c_word_be ) ,
770 Component( 0 , 0 , 0 , 2 , 5 , 5 , c_word_be ) ,
771 Component( 0 , 0 , 0 , 2 , 5 , 0 , c_word_be ) ) ,
772 Format( V4L2_PIX_FMT_BGR32 ,
"bgr32" ,
Format::rgb ,
773 Component( 2 , 0 , 0 , 4 , 8 , 0 , c_byte ) ,
774 Component( 1 , 0 , 0 , 4 , 8 , 0 , c_byte ) ,
775 Component( 0 , 0 , 0 , 4 , 8 , 0 , c_byte ) ) ,
776 Format( V4L2_PIX_FMT_RGB32 ,
"rgb32" ,
Format::rgb ,
777 Component( 1 , 0 , 0 , 4 , 8 , 0 , c_byte ) ,
778 Component( 2 , 0 , 0 , 4 , 8 , 0 , c_byte ) ,
779 Component( 3 , 0 , 0 , 4 , 8 , 0 , c_byte ) ) ,
781 Format( V4L2_PIX_FMT_GREY ,
"grey" , Format::grey ,
782 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
783 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_byte ) ,
784 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_byte ) ) ,
785 Format( V4L2_PIX_FMT_Y10 ,
"y10" , Format::grey ,
786 Component( 0 , 0 , 0 , 1 , 10 , 0 , c_word_le ) ,
787 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_word_le ) ,
788 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_word_le ) ) ,
789 Format( V4L2_PIX_FMT_Y12 ,
"y12" , Format::grey ,
790 Component( 0 , 0 , 0 , 1 , 12 , 0 , c_word_le ) ,
791 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_word_le ) ,
792 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_word_le ) ) ,
793 Format( V4L2_PIX_FMT_Y16 ,
"y16" , Format::grey ,
794 Component( 0 , 0 , 0 , 1 , 16 , 0 , c_word_le ) ,
795 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_word_le ) ,
796 Component( 0 , 0 , 0 , 1 , 0 , 0 , c_word_le ) ) ,
799 Component( 0 , 0 , 0 , 2 , 8 , 0 , c_byte ) ,
800 Component( 1 , 1 , 0 , 4 , 8 , 0 , c_byte ) ,
801 Component( 3 , 1 , 0 , 4 , 8 , 0 , c_byte ) ) ,
803 Component( 0 , 0 , 0 , 2 , 8 , 0 , c_byte ) ,
804 Component( 3 , 1 , 0 , 4 , 8 , 0 , c_byte ) ,
805 Component( 1 , 1 , 0 , 4 , 8 , 0 , c_byte ) ) ,
807 Component( 1 , 0 , 0 , 2 , 8 , 0 , c_byte ) ,
808 Component( 0 , 1 , 0 , 4 , 8 , 0 , c_byte ) ,
809 Component( 2 , 1 , 0 , 4 , 8 , 0 , c_byte ) ) ,
811 Component( 1 , 0 , 0 , 2 , 8 , 0 , c_byte ) ,
812 Component( 2 , 1 , 0 , 4 , 8 , 0 , c_byte ) ,
813 Component( 0 , 1 , 0 , 4 , 8 , 0 , c_byte ) ) ,
814 Format( V4L2_PIX_FMT_YVU420 ,
"yvu420" ,
Format::yuv ,
815 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
816 Component( XY+XY4 , 1 , 1 , 1 , 8 , 0 , c_byte , 1 ) ,
817 Component( XY , 1 , 1 , 1 , 8 , 0 , c_byte , 1 ) ) ,
818 Format( V4L2_PIX_FMT_YUV420 ,
"yuv420" ,
Format::yuv ,
819 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
820 Component( XY , 1 , 1 , 1 , 8 , 0 , c_byte , 1 ) ,
821 Component( XY+XY4 , 1 , 1 , 1 , 8 , 0 , c_byte , 1 ) ) ,
822 Format( V4L2_PIX_FMT_YVU410 ,
"yvu410" ,
Format::yuv ,
823 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
824 Component( XY+XY8 , 2 , 2 , 1 , 8 , 0 , c_byte , 2 ) ,
825 Component( XY , 2 , 2 , 1 , 8 , 0 , c_byte , 2 ) ) ,
826 Format( V4L2_PIX_FMT_YUV410 ,
"yuv410" ,
Format::yuv ,
827 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
828 Component( XY , 2 , 2 , 1 , 8 , 0 , c_byte , 2 ) ,
829 Component( XY+XY8 , 2 , 2 , 1 , 8 , 0 , c_byte , 2 ) ) ,
830 Format( V4L2_PIX_FMT_YUV422P ,
"yuv422p" ,
Format::yuv ,
831 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
832 Component( XY , 1 , 0 , 1 , 8 , 0 , c_byte , 1 ) ,
833 Component( XY+XY2 , 1 , 0 , 1 , 8 , 0 , c_byte , 1 ) ) ,
834 Format( V4L2_PIX_FMT_YUV411P ,
"yuv411p" ,
Format::yuv ,
835 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
836 Component( XY , 2 , 0 , 1 , 8 , 0 , c_byte , 2 ) ,
837 Component( XY+XY4 , 2 , 0 , 1 , 8 , 0 , c_byte , 2 ) ) ,
839 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
840 Component( XY , 1 , 1 , 2 , 8 , 0 , c_byte , 0 ) ,
841 Component( XY+1 , 1 , 1 , 2 , 8 , 0 , c_byte , 0 ) ) ,
843 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
844 Component( XY+1 , 1 , 1 , 2 , 8 , 0 , c_byte , 0 ) ,
845 Component( XY , 1 , 1 , 2 , 8 , 0 , c_byte , 0 ) ) ,
847 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
848 Component( XY , 1 , 0 , 2 , 8 , 0 , c_byte , 0 ) ,
849 Component( XY+1 , 1 , 0 , 2 , 8 , 0 , c_byte , 0 ) ) ,
851 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
852 Component( XY+1 , 1 , 0 , 2 , 8 , 0 , c_byte , 0 ) ,
853 Component( XY , 1 , 0 , 2 , 8 , 0 , c_byte , 0 ) ) ,
855 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
856 Component( XY , 0 , 0 , 2 , 8 , 0 , c_byte , -1 ) ,
857 Component( XY+1 , 0 , 0 , 2 , 8 , 0 , c_byte , -1 ) ) ,
859 Component( 0 , 0 , 0 , 1 , 8 , 0 , c_byte ) ,
860 Component( XY+1 , 0 , 0 , 2 , 8 , 0 , c_byte , -1 ) ,
861 Component( XY , 0 , 0 , 2 , 8 , 0 , c_byte , -1 ) )
865 size_t n =
sizeof(ff)/
sizeof(ff[0]) ;
866 format.reserve( n ) ;
867 for(
unsigned int f = 0 ; f < n ; f++ )
868 format.push_back( ff[f] ) ;
871 std::stable_sort( format.begin() , format.end() , format_less ) ;
874 for(
unsigned int f = 0 ; f < format.size() ; f++ )
876 G_LOG(
"Gv::CaptureV4l::init_device: supported format: "
877 <<
"index=" << f <<
" "
878 <<
"name=[" << format[f].name() <<
"] "
879 <<
"pixelformat=" << format[f].
id() <<
" "
880 <<
"fourcc=[" << fourcc(format[f].
id()) <<
"] "
881 <<
"type=" <<
int(format[f].type()) ) ;
891 CaptureBufferScale scale ;
892 for(
unsigned int f = 0 ; f < format.size() ; f++ )
894 int i = (f+first_format) % format.size() ;
896 if( CaptureImp::set_format( &fmt , m_fd , dx , dy , format[i].
id() , format[i].name() ) )
898 G_LOG(
"Gv::CaptureV4l::init_device: format accepted by device: "
899 <<
"index=" << i <<
" "
900 <<
"name=[" << format[i].name() <<
"] "
901 <<
"pixelformat=" << format[i].
id() <<
" "
902 <<
"fourcc=[" << fourcc(format[i].
id()) <<
"] "
903 <<
"sizeimage=" << fmt.fmt.pix.sizeimage <<
" "
904 <<
"bytesperline=" << fmt.fmt.pix.bytesperline <<
" "
905 <<
"(" << fmt.fmt.pix.width <<
"x" << fmt.fmt.pix.height <<
")"
908 m_dx = fmt.fmt.pix.width ;
909 m_dy = fmt.fmt.pix.height ;
910 m_format = format[i] ;
911 scale = CaptureBufferScale( fmt.fmt.pix.sizeimage , fmt.fmt.pix.bytesperline , fmt.fmt.pix.width , fmt.fmt.pix.height ) ;
916 G_LOG(
"Gv::CaptureV4l::init_device: format rejected by device: "
917 <<
"index=" << i <<
" "
918 <<
"name=[" << format[i].name() <<
"] "
919 <<
"pixelformat=" << format[i].
id() <<
" "
920 <<
"fourcc=[" << fourcc(format[i].
id()) <<
"]: rejected" ) ;
923 if( scale.m_buffersize == 0U )
924 throw Capture::Error(
"failed to negotiate a pixel format" ) ;
928 bool Gv::CaptureImp::set_format( v4l2_format * out_p ,
int fd ,
unsigned int dx ,
unsigned int dy ,
929 g_uint32_t pixelformat ,
const char * name )
932 set_format( out_p , fd , dx , dy , pixelformat , V4L2_FIELD_NONE , name ,
"none" ) ||
933 set_format( out_p , fd , dx , dy , pixelformat , V4L2_FIELD_INTERLACED , name ,
"interlaced" ) ||
934 set_format( out_p , fd , dx , dy , pixelformat , V4L2_FIELD_SEQ_TB , name ,
"top-bottom" ) ||
935 set_format( out_p , fd , dx , dy , pixelformat , V4L2_FIELD_SEQ_BT , name ,
"bottom-top" ) ||
936 set_format( out_p , fd , dx , dy , pixelformat , V4L2_FIELD_INTERLACED_TB , name ,
"interlaced-top-bottom" ) ||
937 set_format( out_p , fd , dx , dy , pixelformat , V4L2_FIELD_INTERLACED_BT , name ,
"interlaced-bottom-top" ) ||
941 bool Gv::CaptureImp::set_format( v4l2_format * out_p ,
int fd ,
unsigned int dx ,
unsigned int dy ,
942 g_uint32_t pixelformat , g_uint32_t field ,
const char * format_name ,
const char * field_name )
944 static struct v4l2_format zero_fmt ;
945 struct v4l2_format fmt = zero_fmt ;
946 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
947 fmt.fmt.pix.width = dx ? dx : 640 ;
948 fmt.fmt.pix.height = dy ? dy : 480 ;
949 fmt.fmt.pix.pixelformat = pixelformat ;
950 fmt.fmt.pix.field = field ;
952 bool try_ok = CaptureImp::xioctl_ok( fd , VIDIOC_TRY_FMT , &fmt ,
true ) ;
954 fmt.fmt.pix.width > 8 && fmt.fmt.pix.height > 8 &&
955 fmt.fmt.pix.pixelformat == pixelformat && fmt.fmt.pix.field == field ;
959 G_DEBUG(
"Gv::CaptureImp::set_format: ioctl try_fmt: " << try_ok <<
": "
960 << pixelformat <<
"->" << fmt.fmt.pix.pixelformat <<
" "
961 << field <<
"->" << fmt.fmt.pix.field ) ;
965 CaptureImp::xioctl_check( fd , VIDIOC_S_FMT , &fmt ,
true ) ;
967 fmt.fmt.pix.width > 8 && fmt.fmt.pix.height > 8 &&
968 fmt.fmt.pix.pixelformat == pixelformat && fmt.fmt.pix.field == field ;
971 G_DEBUG(
"Gv::CaptureV4l::init_device: format negiotiation: "
972 <<
"[" << format_name <<
"," << field_name <<
"]: " << (ok?
"accepted":
"rejected") ) ;
987 std::pair<int,int> Gv::CaptureImp::xioctl(
int fd ,
int request ,
void * arg ,
bool v )
992 rc = xioctl_imp( fd , request , arg ) ;
993 }
while( rc == -1 && errno == EINTR ) ;
994 int e = rc >= 0 ? 0 : errno ;
998 G_DEBUG(
"Gv::CaptureImp::xioctl: "
999 <<
"fd=" << fd <<
" "
1000 <<
"request=" << xioctl_name(request) <<
"(" << static_cast<unsigned int>(request) <<
") "
1001 <<
"rc=" << rc <<
" "
1002 <<
"errno=" << e ) ;
1004 return std::make_pair( rc , e ) ;
1007 bool Gv::CaptureImp::xioctl_ok(
int fd ,
int request ,
void * arg ,
bool v )
1009 pair_t p = xioctl( fd , request , arg , v ) ;
1010 return p.first >= 0 ;
1013 void Gv::CaptureImp::xioctl_warn(
int fd ,
int request ,
void * arg ,
bool v )
1015 pair_t p = xioctl( fd , request , arg , v ) ;
1017 G_WARNING(
"CaptureImp::xioctl: ioctl " << xioctl_name(request) <<
": " << G::Process::strerror(p.second) ) ;
1020 void Gv::CaptureImp::xioctl_check(
int fd ,
int request ,
void * arg ,
bool v )
1022 pair_t p = xioctl( fd , request , arg , v ) ;
1024 throw_errno( xioctl_name(request) , p.second ) ;
1027 bool Gv::CaptureImp::xioctl_eagain(
int fd ,
int request ,
void * arg ,
bool v )
1029 pair_t p = xioctl( fd , request , arg , v ) ;
1032 if( p.second == EAGAIN )
return true ;
1033 throw_errno( xioctl_name(request) , p.second ) ;
1038 void Gv::CaptureImp::xioctl_einval(
int fd ,
int request ,
void * arg ,
const std::string & more ,
bool v )
1040 pair_t p = xioctl( fd , request , arg , v ) ;
1043 if( p.second == EINVAL )
1044 throw Capture::Error( more ) ;
1045 throw_errno( xioctl_name(request) , p.second ) ;
1049 const char * Gv::CaptureImp::xioctl_name(
int request )
1051 for(
const ioctl_name * np = ioctl_names ; np->p ; np++ )
1053 if( static_cast<int>(np->n) == request )
1059 void Gv::CaptureImp::throw_errno(
const char * op ,
int e )
1061 std::ostringstream ss ;
1062 ss << op <<
" error " << e <<
", " << G::Process::strerror(e) ;
1064 ss <<
" (not enough spare usb bandwidth)" ;
1066 throw Capture::NoDevice( ss.str() ) ;
1068 throw Capture::Error( ss.str() ) ;
1071 bool Gv::CaptureImp::m_use_libv4l = true ;
1073 int Gv::CaptureImp::xioctl_imp(
int fd ,
int request ,
void * arg )
1075 return m_use_libv4l ? v4l2_ioctl( fd , request , arg ) : ::ioctl( fd , request , arg ) ;
1078 int Gv::CaptureImp::open(
const char * p ,
int n , mode_t mode )
1083 fd = m_use_libv4l ? v4l2_open( p , n , mode ) : ::open( p , n , mode ) ;
1085 Cleanup::add( fd , m_use_libv4l ) ;
1089 void Gv::CaptureImp::close(
int fd )
1091 if( m_use_libv4l ) v4l2_close( fd ) ; else ::close( fd ) ;
1092 Cleanup::remove( fd ) ;
1095 void * Gv::CaptureImp::mmap(
void * p ,
size_t n ,
int prot ,
int flags ,
int fd , off_t offset )
1098 return m_use_libv4l ? v4l2_mmap( p , n , prot , flags , fd , offset ) : ::mmap( p , n , prot , flags , fd , offset ) ;
1101 int Gv::CaptureImp::read(
int fd ,
void * buffer ,
size_t n )
1103 return m_use_libv4l ? v4l2_read( fd , buffer , n ) : ::read( fd , buffer , n ) ;
1108 Gv::CaptureRequeuer::CaptureRequeuer(
int fd , buffer_type & buffer ) :
1114 Gv::CaptureRequeuer::~CaptureRequeuer()
1116 CaptureImp::xioctl_warn( m_fd , VIDIOC_QBUF , &m_buffer ) ;
1123 Gv::CaptureImp::Cleanup::List Gv::CaptureImp::Cleanup::m_list_lib ;
1124 Gv::CaptureImp::Cleanup::List Gv::CaptureImp::Cleanup::m_list_raw ;
1126 void Gv::CaptureImp::Cleanup::fn(
G::SignalSafe ,
const char * )
1128 for( List::iterator p = m_list_lib.begin() ; p != m_list_lib.end() ; ++p )
1130 for( List::iterator p = m_list_raw.begin() ; p != m_list_raw.end() ; ++p )
1134 void Gv::CaptureImp::Cleanup::add(
int fd ,
bool lib )
1136 static bool first = true ;
1142 List & list = lib ? m_list_lib : m_list_raw ;
1143 list.push_back( fd ) ;
1146 void Gv::CaptureImp::Cleanup::remove(
int fd )
1148 m_list_lib.erase( std::remove(m_list_lib.begin(),m_list_lib.end(),fd) , m_list_lib.end() ) ;
1149 m_list_raw.erase( std::remove(m_list_raw.begin(),m_list_raw.end(),fd) , m_list_raw.end() ) ;
triple< unsigned char > rgb(triple< unsigned char > yuv) g__noexcept
A top-level function that calculates rgb from yuv with default implementation options.
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
An empty structure that is used to indicate a signal-safe, reentrant implementation.
unsigned short xshift() const
Returns the x_shift.
unsigned short yshift() const
Returns the y_shift.
A RAII class to do ioctl(VIDIOC_QBUF) on a v4l buffer.
virtual unsigned int dy() const override
Override from Gv::Capture.
virtual bool simple() const override
Override from Gv::Capture.
A class which acquires the process's special privileges on construction and releases them on destruct...
virtual unsigned int dx() const override
Override from Gv::Capture.
virtual bool active() const override
Override from Gv::Capture.
static std::string tail(const std::string &in, std::string::size_type pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
CaptureV4l(const std::string &dev_name, const std::string &dev_config)
Constructor.
void setFormat(const CaptureBufferFormat &, const CaptureBufferScale &)
Used by the Gv::Capture class to imbue the buffer with a particular format description and scale...
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
A video-capture buffer class to hold image data, with overloaded constructors for the various V4l i/o...
static std::string head(const std::string &in, std::string::size_type pos, const std::string &default_=std::string())
Returns the first part of the string up to just before the given position.
static bool splitMatch(const std::string &in, const std::string &s, const std::string &ws=Str::ws())
Returns true if any of the split parts of 'in' are equal to 's'.
A structure holding capture buffer dimensions.
static std::string trimmed(const std::string &s, const std::string &ws)
Returns a trim()med version of s.
virtual bool read(unsigned char *, size_t) override
Override from Gv::Capture.
A callback interface for the Gv::Capture class.
triple< unsigned char > yuv(triple< unsigned char > rgb) g__noexcept
A top-level function that calculates yuv from rgb with default implementation options.
unsigned short depth() const
Returns the depth.
A private implementation class used by Gv::CaptureV4l.
virtual std::string info() const override
Override from Gv::Capture.
static std::string ws()
A convenience function returning standard whitespace characters.
static void add(void(*fn)(SignalSafe, const char *), const char *arg)
Adds the given handler to the list of handlers that are to be called when the process terminates abno...
virtual int fd() const override
Override from Gv::Capture.
virtual void stop() override
Override from Gv::Capture.
virtual void start() override
Override from Gv::Capture.