2003-03-26 19:57:29 +08:00
//
// ZoneMinder Local Camera Class Implementation, $Date$, $Revision$
2008-07-25 17:33:23 +08:00
// Copyright (C) 2001-2008 Philip Coombes
2003-03-26 19:57:29 +08:00
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
2011-02-16 05:59:06 +08:00
# include "zm.h"
# if ZM_HAS_V4L
2009-01-27 19:07:24 +08:00
# include "zm_local_camera.h"
2003-03-26 19:57:29 +08:00
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <sys/mman.h>
2009-03-24 05:56:30 +08:00
# include <errno.h>
2011-09-08 23:39:58 +08:00
# include <stdlib.h>
# include <limits.h>
2003-03-26 19:57:29 +08:00
2015-04-21 00:53:02 +08:00
/* Workaround for GNU/kFreeBSD */
# if defined(__FreeBSD_kernel__)
# ifndef ENODATA
# define ENODATA ENOATTR
# endif
# endif
2011-05-05 17:52:00 +08:00
static unsigned int BigEndian ;
2008-07-21 23:20:52 +08:00
static int vidioctl ( int fd , int request , void * arg )
{
2009-01-27 19:07:24 +08:00
int result = - 1 ;
do
{
result = ioctl ( fd , request , arg ) ;
} while ( result = = - 1 & & errno = = EINTR ) ;
return ( result ) ;
2008-07-21 23:20:52 +08:00
}
2009-02-13 05:33:05 +08:00
# if HAVE_LIBSWSCALE
2015-11-04 09:46:26 +08:00
static _AVPIXELFORMAT getFfPixFormatFromV4lPalette ( int v4l_version , int palette )
2003-03-26 19:57:29 +08:00
{
2015-11-04 09:46:26 +08:00
_AVPIXELFORMAT pixFormat = AV_PIX_FMT_NONE ;
2011-05-05 17:52:00 +08:00
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
2009-01-28 17:48:06 +08:00
switch ( palette )
{
2015-11-03 08:58:23 +08:00
# if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444)
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_RGB444 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB444 ;
2009-01-28 17:48:06 +08:00
break ;
2009-02-04 23:02:47 +08:00
# endif // V4L2_PIX_FMT_RGB444
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_RGB555 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB555 ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_RGB565 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB565 ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_BGR24 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_BGR24 ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_RGB24 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB24 ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_BGR32 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_BGRA ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_RGB32 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_ARGB ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_GREY :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_GRAY8 ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_YUYV :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUYV422 ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_YUV422P :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV422P ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_YUV411P :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV411P ;
2009-01-28 17:48:06 +08:00
break ;
2009-02-04 23:02:47 +08:00
# ifdef V4L2_PIX_FMT_YUV444
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_YUV444 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV444P ;
2009-01-28 17:48:06 +08:00
break ;
2009-02-04 23:02:47 +08:00
# endif // V4L2_PIX_FMT_YUV444
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_YUV410 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV410P ;
2009-01-28 17:48:06 +08:00
break ;
case V4L2_PIX_FMT_YUV420 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV420P ;
2009-01-28 17:48:06 +08:00
break ;
2009-01-28 20:50:37 +08:00
case V4L2_PIX_FMT_JPEG :
2011-07-01 23:01:24 +08:00
case V4L2_PIX_FMT_MJPEG :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUVJ444P ;
2009-01-28 20:50:37 +08:00
break ;
2013-12-10 21:13:48 +08:00
case V4L2_PIX_FMT_UYVY :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_UYVY422 ;
2013-12-10 21:13:48 +08:00
break ;
2009-01-28 17:48:06 +08:00
// These don't seem to have ffmpeg equivalents
// See if you can match any of the ones in the default clause below!?
case V4L2_PIX_FMT_RGB332 :
case V4L2_PIX_FMT_RGB555X :
case V4L2_PIX_FMT_RGB565X :
2009-02-04 23:02:47 +08:00
//case V4L2_PIX_FMT_Y16 :
//case V4L2_PIX_FMT_PAL8 :
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_YVU410 :
case V4L2_PIX_FMT_YVU420 :
case V4L2_PIX_FMT_Y41P :
2009-02-04 23:02:47 +08:00
//case V4L2_PIX_FMT_YUV555 :
//case V4L2_PIX_FMT_YUV565 :
//case V4L2_PIX_FMT_YUV32 :
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_NV12 :
case V4L2_PIX_FMT_NV21 :
case V4L2_PIX_FMT_YYUV :
case V4L2_PIX_FMT_HI240 :
case V4L2_PIX_FMT_HM12 :
2009-02-04 23:02:47 +08:00
//case V4L2_PIX_FMT_SBGGR8 :
//case V4L2_PIX_FMT_SGBRG8 :
//case V4L2_PIX_FMT_SBGGR16 :
2009-01-28 17:48:06 +08:00
case V4L2_PIX_FMT_DV :
case V4L2_PIX_FMT_MPEG :
case V4L2_PIX_FMT_WNVA :
case V4L2_PIX_FMT_SN9C10X :
case V4L2_PIX_FMT_PWC1 :
case V4L2_PIX_FMT_PWC2 :
case V4L2_PIX_FMT_ET61X251 :
2009-02-04 23:02:47 +08:00
//case V4L2_PIX_FMT_SPCA501 :
//case V4L2_PIX_FMT_SPCA505 :
//case V4L2_PIX_FMT_SPCA508 :
//case V4L2_PIX_FMT_SPCA561 :
//case V4L2_PIX_FMT_PAC207 :
//case V4L2_PIX_FMT_PJPG :
//case V4L2_PIX_FMT_YVYU :
2009-01-28 17:48:06 +08:00
default :
{
Fatal ( " Can't find swscale format for palette %d " , palette ) ;
break ;
// These are all spare and may match some of the above
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUVJ420P ;
pixFormat = AV_PIX_FMT_YUVJ422P ;
pixFormat = AV_PIX_FMT_UYVY422 ;
pixFormat = AV_PIX_FMT_UYYVYY411 ;
pixFormat = AV_PIX_FMT_BGR565 ;
pixFormat = AV_PIX_FMT_BGR555 ;
pixFormat = AV_PIX_FMT_BGR8 ;
pixFormat = AV_PIX_FMT_BGR4 ;
pixFormat = AV_PIX_FMT_BGR4_BYTE ;
pixFormat = AV_PIX_FMT_RGB8 ;
pixFormat = AV_PIX_FMT_RGB4 ;
pixFormat = AV_PIX_FMT_RGB4_BYTE ;
pixFormat = AV_PIX_FMT_NV12 ;
pixFormat = AV_PIX_FMT_NV21 ;
pixFormat = AV_PIX_FMT_RGB32_1 ;
pixFormat = AV_PIX_FMT_BGR32_1 ;
pixFormat = AV_PIX_FMT_GRAY16BE ;
pixFormat = AV_PIX_FMT_GRAY16LE ;
pixFormat = AV_PIX_FMT_YUV440P ;
pixFormat = AV_PIX_FMT_YUVJ440P ;
pixFormat = AV_PIX_FMT_YUVA420P ;
//pixFormat = AV_PIX_FMT_VDPAU_H264;
//pixFormat = AV_PIX_FMT_VDPAU_MPEG1;
//pixFormat = AV_PIX_FMT_VDPAU_MPEG2;
2009-01-28 17:48:06 +08:00
}
}
2009-02-13 05:33:05 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
{
switch ( palette )
{
2011-04-29 22:26:50 +08:00
case VIDEO_PALETTE_RGB32 :
if ( BigEndian )
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_ARGB ;
2011-04-29 22:26:50 +08:00
else
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_BGRA ;
2011-04-29 22:26:50 +08:00
break ;
case VIDEO_PALETTE_RGB24 :
if ( BigEndian )
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB24 ;
2011-04-29 22:26:50 +08:00
else
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_BGR24 ;
2011-04-29 22:26:50 +08:00
break ;
case VIDEO_PALETTE_GREY :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_GRAY8 ;
2011-04-29 22:26:50 +08:00
break ;
2009-02-13 05:33:05 +08:00
case VIDEO_PALETTE_RGB555 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB555 ;
2009-02-13 05:33:05 +08:00
break ;
case VIDEO_PALETTE_RGB565 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_RGB565 ;
2009-02-13 05:33:05 +08:00
break ;
case VIDEO_PALETTE_YUYV :
case VIDEO_PALETTE_YUV422 :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUYV422 ;
2009-02-13 05:33:05 +08:00
break ;
case VIDEO_PALETTE_YUV422P :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV422P ;
2009-02-13 05:33:05 +08:00
break ;
case VIDEO_PALETTE_YUV420P :
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUV420P ;
2009-02-13 05:33:05 +08:00
break ;
default :
{
Fatal ( " Can't find swscale format for palette %d " , palette ) ;
break ;
// These are all spare and may match some of the above
2015-11-03 08:58:23 +08:00
pixFormat = AV_PIX_FMT_YUVJ420P ;
pixFormat = AV_PIX_FMT_YUVJ422P ;
pixFormat = AV_PIX_FMT_YUVJ444P ;
pixFormat = AV_PIX_FMT_UYVY422 ;
pixFormat = AV_PIX_FMT_UYYVYY411 ;
pixFormat = AV_PIX_FMT_BGR565 ;
pixFormat = AV_PIX_FMT_BGR555 ;
pixFormat = AV_PIX_FMT_BGR8 ;
pixFormat = AV_PIX_FMT_BGR4 ;
pixFormat = AV_PIX_FMT_BGR4_BYTE ;
pixFormat = AV_PIX_FMT_RGB8 ;
pixFormat = AV_PIX_FMT_RGB4 ;
pixFormat = AV_PIX_FMT_RGB4_BYTE ;
pixFormat = AV_PIX_FMT_NV12 ;
pixFormat = AV_PIX_FMT_NV21 ;
pixFormat = AV_PIX_FMT_RGB32_1 ;
pixFormat = AV_PIX_FMT_BGR32_1 ;
pixFormat = AV_PIX_FMT_GRAY16BE ;
pixFormat = AV_PIX_FMT_GRAY16LE ;
pixFormat = AV_PIX_FMT_YUV440P ;
pixFormat = AV_PIX_FMT_YUVJ440P ;
pixFormat = AV_PIX_FMT_YUVA420P ;
//pixFormat = AV_PIX_FMT_VDPAU_H264;
//pixFormat = AV_PIX_FMT_VDPAU_MPEG1;
//pixFormat = AV_PIX_FMT_VDPAU_MPEG2;
2009-02-13 05:33:05 +08:00
}
}
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
return ( pixFormat ) ;
}
# endif // HAVE_LIBSWSCALE
2011-07-02 20:32:16 +08:00
# if ZM_HAS_V4L2
static char palette_desc [ 32 ] ;
2015-04-19 18:38:23 +08:00
/* Automatic format selection preferred formats */
2011-07-02 20:32:16 +08:00
static const uint32_t prefered_rgb32_formats [ ] = { V4L2_PIX_FMT_BGR32 , V4L2_PIX_FMT_RGB32 , V4L2_PIX_FMT_BGR24 , V4L2_PIX_FMT_RGB24 , V4L2_PIX_FMT_YUYV , V4L2_PIX_FMT_UYVY , V4L2_PIX_FMT_JPEG , V4L2_PIX_FMT_MJPEG , V4L2_PIX_FMT_YUV422P , V4L2_PIX_FMT_YUV420 } ;
static const uint32_t prefered_rgb24_formats [ ] = { V4L2_PIX_FMT_BGR24 , V4L2_PIX_FMT_RGB24 , V4L2_PIX_FMT_YUYV , V4L2_PIX_FMT_UYVY , V4L2_PIX_FMT_JPEG , V4L2_PIX_FMT_MJPEG , V4L2_PIX_FMT_YUV422P , V4L2_PIX_FMT_YUV420 } ;
static const uint32_t prefered_gray8_formats [ ] = { V4L2_PIX_FMT_GREY , V4L2_PIX_FMT_YUYV , V4L2_PIX_FMT_UYVY , V4L2_PIX_FMT_JPEG , V4L2_PIX_FMT_MJPEG , V4L2_PIX_FMT_YUV422P , V4L2_PIX_FMT_YUV420 } ;
# endif
2009-02-13 05:33:05 +08:00
int LocalCamera : : camera_count = 0 ;
int LocalCamera : : channel_count = 0 ;
2009-02-13 06:26:28 +08:00
int LocalCamera : : channels [ VIDEO_MAX_FRAME ] ;
int LocalCamera : : standards [ VIDEO_MAX_FRAME ] ;
2009-02-13 05:33:05 +08:00
int LocalCamera : : vid_fd = - 1 ;
int LocalCamera : : v4l_version = 0 ;
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
LocalCamera : : V4L2Data LocalCamera : : v4l2_data ;
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
LocalCamera : : V4L1Data LocalCamera : : v4l1_data ;
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
# if HAVE_LIBSWSCALE
2009-02-18 20:30:43 +08:00
AVFrame * * LocalCamera : : capturePictures = 0 ;
2009-01-28 17:48:06 +08:00
# endif // HAVE_LIBSWSCALE
2009-02-13 05:33:05 +08:00
LocalCamera * LocalCamera : : last_camera = NULL ;
2014-07-14 04:39:27 +08:00
LocalCamera : : LocalCamera ( int p_id , const std : : string & p_device , int p_channel , int p_standard , bool p_v4l_multi_buffer , unsigned int p_v4l_captures_per_frame , const std : : string & p_method , int p_width , int p_height , int p_colours , int p_palette , int p_brightness , int p_contrast , int p_hue , int p_colour , bool p_capture , unsigned int p_extras ) :
2011-04-29 22:26:50 +08:00
Camera ( p_id , LOCAL_SRC , p_width , p_height , p_colours , ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR ( p_colours ) , p_brightness , p_contrast , p_hue , p_colour , p_capture ) ,
2009-02-13 05:33:05 +08:00
device ( p_device ) ,
channel ( p_channel ) ,
standard ( p_standard ) ,
2009-02-13 06:26:28 +08:00
palette ( p_palette ) ,
2012-01-30 14:00:22 +08:00
channel_index ( 0 ) ,
extras ( p_extras )
2009-02-13 05:33:05 +08:00
{
// If we are the first, or only, input on this device then
// do the initial opening etc
device_prime = ( camera_count + + = = 0 ) ;
2011-05-05 17:52:00 +08:00
v4l_version = ( p_method = = " v4l2 " ? 2 : 1 ) ;
2014-07-14 04:39:27 +08:00
v4l_multi_buffer = p_v4l_multi_buffer ;
v4l_captures_per_frame = p_v4l_captures_per_frame ;
2011-05-05 17:52:00 +08:00
2009-02-13 05:33:05 +08:00
if ( capture )
{
2011-08-01 03:15:38 +08:00
if ( device_prime )
2009-02-13 05:33:05 +08:00
{
2011-02-16 05:59:06 +08:00
Debug ( 2 , " V4L support enabled, using V4L%d api " , v4l_version ) ;
2009-02-13 05:33:05 +08:00
}
if ( ! last_camera | | channel ! = last_camera - > channel )
{
// We are the first, or only, input that uses this channel
channel_prime = true ;
2009-02-13 06:26:28 +08:00
channel_index = channel_count + + ;
channels [ channel_index ] = channel ;
standards [ channel_index ] = standard ;
2009-02-13 05:33:05 +08:00
}
else
{
// We are the second, or subsequent, input using this channel
channel_prime = false ;
}
2011-04-29 22:26:50 +08:00
2011-05-05 17:52:00 +08:00
}
/* The V4L1 API doesn't care about endianness, we need to check the endianness of the machine */
2011-04-29 22:26:50 +08:00
uint32_t checkval = 0xAABBCCDD ;
2011-05-05 17:52:00 +08:00
if ( * ( unsigned char * ) & checkval = = 0xDD ) {
2011-04-29 22:26:50 +08:00
BigEndian = 0 ;
2011-05-05 17:52:00 +08:00
Debug ( 2 , " little-endian processor detected " ) ;
} else if ( * ( unsigned char * ) & checkval = = 0xAA ) {
2011-04-29 22:26:50 +08:00
BigEndian = 1 ;
2011-05-05 17:52:00 +08:00
Debug ( 2 , " Big-endian processor detected " ) ;
} else {
2011-04-29 22:26:50 +08:00
Error ( " Unable to detect the processor's endianness. Assuming little-endian. " ) ;
BigEndian = 0 ;
2011-05-05 17:52:00 +08:00
}
2011-07-02 20:32:16 +08:00
# if ZM_HAS_V4L2
if ( v4l_version = = 2 & & palette = = 0 ) {
/* Use automatic format selection */
Debug ( 2 , " Using automatic format selection " ) ;
palette = AutoSelectFormat ( colours ) ;
if ( palette = = 0 ) {
Error ( " Automatic format selection failed. Falling back to YUYV " ) ;
palette = V4L2_PIX_FMT_YUYV ;
} else {
2012-03-07 21:02:27 +08:00
if ( capture ) {
Info ( " Selected capture palette: %s (%c%c%c%c) " , palette_desc , palette & 0xff , ( palette > > 8 ) & 0xff , ( palette > > 16 ) & 0xff , ( palette > > 24 ) & 0xff ) ;
}
2011-07-02 20:32:16 +08:00
}
}
# endif
2011-05-05 17:52:00 +08:00
2011-08-01 03:15:38 +08:00
if ( capture ) {
if ( last_camera ) {
if ( ( p_method = = " v4l2 " & & v4l_version ! = 2 ) | | ( p_method = = " v4l1 " & & v4l_version ! = 1 ) )
Fatal ( " Different Video For Linux version used for monitors sharing same device " ) ;
if ( standard ! = last_camera - > standard )
Warning ( " Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong " ) ;
if ( palette ! = last_camera - > palette )
Warning ( " Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong " ) ;
if ( width ! = last_camera - > width | | height ! = last_camera - > height )
Warning ( " Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong " ) ;
}
2011-05-05 17:52:00 +08:00
# if HAVE_LIBSWSCALE
2011-05-08 21:32:42 +08:00
/* Get ffmpeg pixel format based on capture palette and endianness */
capturePixFormat = getFfPixFormatFromV4lPalette ( v4l_version , palette ) ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_NONE ;
2011-07-02 20:32:16 +08:00
# endif // HAVE_LIBSWSCALE
2014-07-14 04:39:27 +08:00
}
2009-02-13 05:33:05 +08:00
2011-05-05 17:52:00 +08:00
/* V4L2 format matching */
2011-04-29 22:26:50 +08:00
# if ZM_HAS_V4L2
if ( v4l_version = = 2 ) {
2011-05-05 17:52:00 +08:00
/* Try to find a match for the selected palette and target colourspace */
/* RGB32 palette and 32bit target colourspace */
if ( palette = = V4L2_PIX_FMT_RGB32 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_type = 0 ;
subpixelorder = ZM_SUBPIX_ORDER_ARGB ;
/* BGR32 palette and 32bit target colourspace */
} else if ( palette = = V4L2_PIX_FMT_BGR32 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_type = 0 ;
subpixelorder = ZM_SUBPIX_ORDER_BGRA ;
/* RGB24 palette and 24bit target colourspace */
} else if ( palette = = V4L2_PIX_FMT_RGB24 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_type = 0 ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
/* BGR24 palette and 24bit target colourspace */
} else if ( palette = = V4L2_PIX_FMT_BGR24 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_type = 0 ;
subpixelorder = ZM_SUBPIX_ORDER_BGR ;
/* Grayscale palette and grayscale target colourspace */
} else if ( palette = = V4L2_PIX_FMT_GREY & & colours = = ZM_COLOUR_GRAY8 ) {
conversion_type = 0 ;
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2011-05-06 20:01:16 +08:00
/* Unable to find a solution for the selected palette and target colourspace. Conversion required. Notify the user of performance penalty */
2011-05-05 17:52:00 +08:00
} else {
2011-05-07 23:39:16 +08:00
if ( capture )
2015-02-22 01:02:38 +08:00
# if HAVE_LIBSWSCALE
2015-02-11 00:53:50 +08:00
Info ( " No direct match for the selected palette (%c%c%c%c) and target colorspace (%d). Format conversion is required, performance penalty expected " , ( capturePixFormat ) & 0xff , ( ( capturePixFormat > > 8 ) & 0xff ) , ( ( capturePixFormat > > 16 ) & 0xff ) , ( ( capturePixFormat > > 24 ) & 0xff ) , colours ) ;
2015-02-22 01:02:38 +08:00
# else
Info ( " No direct match for the selected palette and target colorspace. Format conversion is required, performance penalty expected " ) ;
# endif
2011-04-29 22:26:50 +08:00
# if HAVE_LIBSWSCALE
2011-05-06 20:01:16 +08:00
/* Try using swscale for the conversion */
2011-05-05 17:52:00 +08:00
conversion_type = 1 ;
Debug ( 2 , " Using swscale for image conversion " ) ;
if ( colours = = ZM_COLOUR_RGB32 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_RGBA ;
2011-05-05 17:52:00 +08:00
} else if ( colours = = ZM_COLOUR_RGB24 ) {
2011-04-29 22:26:50 +08:00
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_RGB24 ;
2011-05-05 17:52:00 +08:00
} else if ( colours = = ZM_COLOUR_GRAY8 ) {
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_GRAY8 ;
2011-05-05 17:52:00 +08:00
} else {
Panic ( " Unexpected colours: %d " , colours ) ;
}
2011-05-08 21:32:42 +08:00
if ( capture ) {
2015-05-29 23:38:02 +08:00
# if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
2011-05-08 21:32:42 +08:00
if ( ! sws_isSupportedInput ( capturePixFormat ) ) {
2012-03-07 20:33:09 +08:00
Error ( " swscale does not support the used capture format: %c%c%c%c " , ( capturePixFormat ) & 0xff , ( ( capturePixFormat > > 8 ) & 0xff ) , ( ( capturePixFormat > > 16 ) & 0xff ) , ( ( capturePixFormat > > 24 ) & 0xff ) ) ;
2011-05-08 21:32:42 +08:00
conversion_type = 2 ; /* Try ZM format conversions */
}
if ( ! sws_isSupportedOutput ( imagePixFormat ) ) {
2012-03-07 20:33:09 +08:00
Error ( " swscale does not support the target format: %c%c%c%c " , ( imagePixFormat ) & 0xff , ( ( imagePixFormat > > 8 ) & 0xff ) , ( ( imagePixFormat > > 16 ) & 0xff ) , ( ( imagePixFormat > > 24 ) & 0xff ) ) ;
2011-05-08 21:32:42 +08:00
conversion_type = 2 ; /* Try ZM format conversions */
}
2014-04-26 04:12:58 +08:00
# endif
2011-05-05 17:52:00 +08:00
}
# else
/* Don't have swscale, see what we can do */
conversion_type = 2 ;
2011-04-29 22:26:50 +08:00
# endif
2011-05-06 20:01:16 +08:00
/* Our YUYV->Grayscale conversion is a lot faster than swscale's */
2011-07-01 23:01:24 +08:00
if ( colours = = ZM_COLOUR_GRAY8 & & palette = = V4L2_PIX_FMT_YUYV ) {
2011-05-06 20:01:16 +08:00
conversion_type = 2 ;
}
2011-07-01 23:01:24 +08:00
/* JPEG */
if ( palette = = V4L2_PIX_FMT_JPEG | | palette = = V4L2_PIX_FMT_MJPEG ) {
2011-07-05 23:23:02 +08:00
Debug ( 2 , " Using JPEG image decoding " ) ;
2011-07-01 23:01:24 +08:00
conversion_type = 3 ;
}
2011-05-06 20:01:16 +08:00
if ( conversion_type = = 2 ) {
Debug ( 2 , " Using ZM for image conversion " ) ;
if ( palette = = V4L2_PIX_FMT_RGB32 & & colours = = ZM_COLOUR_GRAY8 ) {
conversion_fptr = & std_convert_argb_gray8 ;
2011-06-08 04:14:01 +08:00
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2011-05-06 20:01:16 +08:00
} else if ( palette = = V4L2_PIX_FMT_BGR32 & & colours = = ZM_COLOUR_GRAY8 ) {
conversion_fptr = & std_convert_bgra_gray8 ;
2011-06-08 04:14:01 +08:00
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2011-05-06 20:01:16 +08:00
} else if ( palette = = V4L2_PIX_FMT_YUYV & & colours = = ZM_COLOUR_GRAY8 ) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
if ( config . cpu_extensions & & sseversion > = 35 ) {
conversion_fptr = & ssse3_convert_yuyv_gray8 ;
Debug ( 2 , " Using SSSE3 YUYV->grayscale fast conversion " ) ;
} else {
conversion_fptr = & std_convert_yuyv_gray8 ;
Debug ( 2 , " Using standard YUYV->grayscale fast conversion " ) ;
}
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
} else if ( palette = = V4L2_PIX_FMT_YUYV & & colours = = ZM_COLOUR_RGB24 ) {
conversion_fptr = & zm_convert_yuyv_rgb ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else if ( palette = = V4L2_PIX_FMT_YUYV & & colours = = ZM_COLOUR_RGB32 ) {
conversion_fptr = & zm_convert_yuyv_rgba ;
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
} else if ( palette = = V4L2_PIX_FMT_RGB555 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_fptr = & zm_convert_rgb555_rgb ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else if ( palette = = V4L2_PIX_FMT_RGB555 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_fptr = & zm_convert_rgb555_rgba ;
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
} else if ( palette = = V4L2_PIX_FMT_RGB565 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_fptr = & zm_convert_rgb565_rgb ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else if ( palette = = V4L2_PIX_FMT_RGB565 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_fptr = & zm_convert_rgb565_rgba ;
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
} else {
2011-10-26 19:28:07 +08:00
Fatal ( " Unable to find a suitable format conversion for the selected palette and target colorspace. " ) ;
2011-05-06 20:01:16 +08:00
}
}
2011-04-29 22:26:50 +08:00
}
}
# endif // ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
2011-05-05 17:52:00 +08:00
/* V4L1 format matching */
2011-04-29 22:26:50 +08:00
# if ZM_HAS_V4L1
if ( v4l_version = = 1 ) {
2011-05-05 17:52:00 +08:00
/* Try to find a match for the selected palette and target colourspace */
/* RGB32 palette and 32bit target colourspace */
if ( palette = = VIDEO_PALETTE_RGB32 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_type = 0 ;
if ( BigEndian ) {
subpixelorder = ZM_SUBPIX_ORDER_ARGB ;
} else {
subpixelorder = ZM_SUBPIX_ORDER_BGRA ;
}
/* RGB24 palette and 24bit target colourspace */
} else if ( palette = = VIDEO_PALETTE_RGB24 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_type = 0 ;
if ( BigEndian ) {
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else {
subpixelorder = ZM_SUBPIX_ORDER_BGR ;
}
/* Grayscale palette and grayscale target colourspace */
} else if ( palette = = VIDEO_PALETTE_GREY & & colours = = ZM_COLOUR_GRAY8 ) {
conversion_type = 0 ;
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
/* Unable to find a solution for the selected palette and target colourspace. Conversion required. Notify the user of performance penalty */
} else {
2011-05-07 04:07:40 +08:00
if ( capture )
2011-10-26 19:28:07 +08:00
Info ( " No direct match for the selected palette and target colorspace. Format conversion is required, performance penalty expected " ) ;
2011-05-05 17:52:00 +08:00
# if HAVE_LIBSWSCALE
2011-05-06 20:01:16 +08:00
/* Try using swscale for the conversion */
2011-05-05 17:52:00 +08:00
conversion_type = 1 ;
Debug ( 2 , " Using swscale for image conversion " ) ;
if ( colours = = ZM_COLOUR_RGB32 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_RGBA ;
2011-05-05 17:52:00 +08:00
} else if ( colours = = ZM_COLOUR_RGB24 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_RGB24 ;
2011-05-05 17:52:00 +08:00
} else if ( colours = = ZM_COLOUR_GRAY8 ) {
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2015-11-03 08:58:23 +08:00
imagePixFormat = AV_PIX_FMT_GRAY8 ;
2011-05-05 17:52:00 +08:00
} else {
Panic ( " Unexpected colours: %d " , colours ) ;
}
2011-05-08 21:32:42 +08:00
if ( capture ) {
if ( ! sws_isSupportedInput ( capturePixFormat ) ) {
Error ( " swscale does not support the used capture format " ) ;
conversion_type = 2 ; /* Try ZM format conversions */
}
if ( ! sws_isSupportedOutput ( imagePixFormat ) ) {
Error ( " swscale does not support the target format " ) ;
conversion_type = 2 ; /* Try ZM format conversions */
}
2011-05-05 17:52:00 +08:00
}
# else
/* Don't have swscale, see what we can do */
conversion_type = 2 ;
2011-05-06 20:01:16 +08:00
# endif
/* Our YUYV->Grayscale conversion is a lot faster than swscale's */
2011-07-01 23:01:24 +08:00
if ( colours = = ZM_COLOUR_GRAY8 & & ( palette = = VIDEO_PALETTE_YUYV | | palette = = VIDEO_PALETTE_YUV422 ) ) {
2011-05-06 20:01:16 +08:00
conversion_type = 2 ;
}
if ( conversion_type = = 2 ) {
Debug ( 2 , " Using ZM for image conversion " ) ;
if ( palette = = VIDEO_PALETTE_RGB32 & & colours = = ZM_COLOUR_GRAY8 ) {
if ( BigEndian ) {
conversion_fptr = & std_convert_argb_gray8 ;
2011-06-08 04:14:01 +08:00
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2011-05-06 20:01:16 +08:00
} else {
conversion_fptr = & std_convert_bgra_gray8 ;
2011-06-08 04:14:01 +08:00
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
2011-05-06 20:01:16 +08:00
}
} else if ( ( palette = = VIDEO_PALETTE_YUYV | | palette = = VIDEO_PALETTE_YUV422 ) & & colours = = ZM_COLOUR_GRAY8 ) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
if ( config . cpu_extensions & & sseversion > = 35 ) {
conversion_fptr = & ssse3_convert_yuyv_gray8 ;
Debug ( 2 , " Using SSSE3 YUYV->grayscale fast conversion " ) ;
} else {
conversion_fptr = & std_convert_yuyv_gray8 ;
Debug ( 2 , " Using standard YUYV->grayscale fast conversion " ) ;
}
subpixelorder = ZM_SUBPIX_ORDER_NONE ;
} else if ( ( palette = = VIDEO_PALETTE_YUYV | | palette = = VIDEO_PALETTE_YUV422 ) & & colours = = ZM_COLOUR_RGB24 ) {
conversion_fptr = & zm_convert_yuyv_rgb ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else if ( ( palette = = VIDEO_PALETTE_YUYV | | palette = = VIDEO_PALETTE_YUV422 ) & & colours = = ZM_COLOUR_RGB32 ) {
conversion_fptr = & zm_convert_yuyv_rgba ;
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
} else if ( palette = = VIDEO_PALETTE_RGB555 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_fptr = & zm_convert_rgb555_rgb ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else if ( palette = = VIDEO_PALETTE_RGB555 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_fptr = & zm_convert_rgb555_rgba ;
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
} else if ( palette = = VIDEO_PALETTE_RGB565 & & colours = = ZM_COLOUR_RGB24 ) {
conversion_fptr = & zm_convert_rgb565_rgb ;
subpixelorder = ZM_SUBPIX_ORDER_RGB ;
} else if ( palette = = VIDEO_PALETTE_RGB565 & & colours = = ZM_COLOUR_RGB32 ) {
conversion_fptr = & zm_convert_rgb565_rgba ;
subpixelorder = ZM_SUBPIX_ORDER_RGBA ;
2011-04-29 22:26:50 +08:00
} else {
2011-10-26 19:28:07 +08:00
Fatal ( " Unable to find a suitable format conversion for the selected palette and target colorspace. " ) ;
2011-04-29 22:26:50 +08:00
}
2011-05-05 17:52:00 +08:00
}
2011-04-29 22:26:50 +08:00
}
}
2011-05-05 17:52:00 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
2011-05-05 17:52:00 +08:00
last_camera = this ;
Debug ( 3 , " Selected subpixelorder: %d " , subpixelorder ) ;
2009-02-13 05:33:05 +08:00
2009-02-18 20:30:43 +08:00
# if HAVE_LIBSWSCALE
2011-05-08 21:32:42 +08:00
/* Initialize swscale stuff */
if ( capture & & conversion_type = = 1 ) {
2015-05-29 23:38:02 +08:00
# if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
tmpPicture = av_frame_alloc ( ) ;
# else
2011-05-08 21:32:42 +08:00
tmpPicture = avcodec_alloc_frame ( ) ;
2015-05-29 23:38:02 +08:00
# endif
2011-05-08 21:32:42 +08:00
if ( ! tmpPicture )
Fatal ( " Could not allocate temporary picture " ) ;
int pSize = avpicture_get_size ( imagePixFormat , width , height ) ;
2013-03-17 07:45:21 +08:00
if ( ( unsigned int ) pSize ! = imagesize ) {
2011-05-08 21:32:42 +08:00
Fatal ( " Image size mismatch. Required: %d Available: %d " , pSize , imagesize ) ;
}
if ( config . cpu_extensions & & sseversion > = 20 ) {
2015-11-03 08:58:23 +08:00
imgConversionContext = sws_getContext ( width , height , capturePixFormat , width , height , imagePixFormat , SWS_BICUBIC , NULL , NULL , NULL ) ;
2011-05-08 21:32:42 +08:00
} else {
imgConversionContext = sws_getContext ( width , height , capturePixFormat , width , height , imagePixFormat , SWS_BICUBIC , NULL , NULL , NULL ) ;
}
if ( ! imgConversionContext )
Fatal ( " Unable to initialise image scaling context " ) ;
}
# endif
2009-02-13 05:33:05 +08:00
}
LocalCamera : : ~ LocalCamera ( )
{
if ( device_prime & & capture )
Terminate ( ) ;
2011-05-08 21:32:42 +08:00
# if HAVE_LIBSWSCALE
/* Clean up swscale stuff */
if ( capture & & conversion_type = = 1 ) {
sws_freeContext ( imgConversionContext ) ;
imgConversionContext = NULL ;
2015-11-03 08:58:23 +08:00
av_frame_free ( & tmpPicture ) ;
2011-05-08 21:32:42 +08:00
tmpPicture = NULL ;
}
# endif
2009-02-13 05:33:05 +08:00
}
void LocalCamera : : Initialise ( )
{
# if HAVE_LIBSWSCALE
2011-06-21 17:19:10 +08:00
if ( logDebugging ( ) )
2009-02-13 05:33:05 +08:00
av_log_set_level ( AV_LOG_DEBUG ) ;
else
av_log_set_level ( AV_LOG_QUIET ) ;
# endif // HAVE_LIBSWSCALE
struct stat st ;
if ( stat ( device . c_str ( ) , & st ) < 0 )
Fatal ( " Failed to stat video device %s: %s " , device . c_str ( ) , strerror ( errno ) ) ;
if ( ! S_ISCHR ( st . st_mode ) )
Fatal ( " File %s is not device file: %s " , device . c_str ( ) , strerror ( errno ) ) ;
Debug ( 3 , " Opening video device %s " , device . c_str ( ) ) ;
//if ( (vid_fd = open( device.c_str(), O_RDWR|O_NONBLOCK, 0 )) < 0 )
if ( ( vid_fd = open ( device . c_str ( ) , O_RDWR , 0 ) ) < 0 )
Fatal ( " Failed to open video device %s: %s " , device . c_str ( ) , strerror ( errno ) ) ;
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
Debug ( 2 , " V4L2 support enabled, using V4L%d api " , v4l_version ) ;
if ( v4l_version = = 2 )
{
2008-07-21 23:20:52 +08:00
struct v4l2_capability vid_cap ;
Debug ( 3 , " Checking video device capabilities " ) ;
if ( vidioctl ( vid_fd , VIDIOC_QUERYCAP , & vid_cap ) < 0 )
Fatal ( " Failed to query video device: %s " , strerror ( errno ) ) ;
if ( ! ( vid_cap . capabilities & V4L2_CAP_VIDEO_CAPTURE ) )
Fatal ( " Video device is not video capture device " ) ;
if ( ! ( vid_cap . capabilities & V4L2_CAP_STREAMING ) )
Fatal ( " Video device does not support streaming i/o " ) ;
Debug ( 3 , " Setting up video format " ) ;
2004-08-11 23:13:47 +08:00
2008-07-21 23:20:52 +08:00
memset ( & v4l2_data . fmt , 0 , sizeof ( v4l2_data . fmt ) ) ;
v4l2_data . fmt . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2009-01-27 19:07:24 +08:00
if ( vidioctl ( vid_fd , VIDIOC_G_FMT , & v4l2_data . fmt ) < 0 )
Fatal ( " Failed to get video format: %s " , strerror ( errno ) ) ;
2011-01-21 02:49:42 +08:00
Debug ( 4 , " v4l2_data.fmt.type = %08x " , v4l2_data . fmt . type ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.width = %08x " , v4l2_data . fmt . fmt . pix . width ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.height = %08x " , v4l2_data . fmt . fmt . pix . height ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.pixelformat = %08x " , v4l2_data . fmt . fmt . pix . pixelformat ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.field = %08x " , v4l2_data . fmt . fmt . pix . field ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.bytesperline = %08x " , v4l2_data . fmt . fmt . pix . bytesperline ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.sizeimage = %08x " , v4l2_data . fmt . fmt . pix . sizeimage ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.colorspace = %08x " , v4l2_data . fmt . fmt . pix . colorspace ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.priv = %08x " , v4l2_data . fmt . fmt . pix . priv ) ;
2009-01-27 19:07:24 +08:00
v4l2_data . fmt . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2008-07-21 23:20:52 +08:00
v4l2_data . fmt . fmt . pix . width = width ;
v4l2_data . fmt . fmt . pix . height = height ;
2009-01-27 19:07:24 +08:00
v4l2_data . fmt . fmt . pix . pixelformat = palette ;
2008-07-21 23:20:52 +08:00
2012-01-30 14:00:22 +08:00
if ( ( extras & 0xff ) ! = 0 )
2011-06-22 23:38:35 +08:00
{
2012-01-30 14:00:22 +08:00
v4l2_data . fmt . fmt . pix . field = ( v4l2_field ) ( extras & 0xff ) ;
2011-06-22 23:38:35 +08:00
if ( vidioctl ( vid_fd , VIDIOC_S_FMT , & v4l2_data . fmt ) < 0 )
{
2012-01-30 14:00:22 +08:00
Warning ( " Failed to set V4L2 field to %d, falling back to auto " , ( extras & 0xff ) ) ;
2011-06-22 23:38:35 +08:00
v4l2_data . fmt . fmt . pix . field = V4L2_FIELD_ANY ;
if ( vidioctl ( vid_fd , VIDIOC_S_FMT , & v4l2_data . fmt ) < 0 ) {
Fatal ( " Failed to set video format: %s " , strerror ( errno ) ) ;
}
}
} else {
if ( vidioctl ( vid_fd , VIDIOC_S_FMT , & v4l2_data . fmt ) < 0 ) {
Fatal ( " Failed to set video format: %s " , strerror ( errno ) ) ;
}
}
2008-07-21 23:20:52 +08:00
/* Note VIDIOC_S_FMT may change width and height. */
2011-01-21 02:49:42 +08:00
Debug ( 4 , " v4l2_data.fmt.type = %08x " , v4l2_data . fmt . type ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.width = %08x " , v4l2_data . fmt . fmt . pix . width ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.height = %08x " , v4l2_data . fmt . fmt . pix . height ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.pixelformat = %08x " , v4l2_data . fmt . fmt . pix . pixelformat ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.field = %08x " , v4l2_data . fmt . fmt . pix . field ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.bytesperline = %08x " , v4l2_data . fmt . fmt . pix . bytesperline ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.sizeimage = %08x " , v4l2_data . fmt . fmt . pix . sizeimage ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.colorspace = %08x " , v4l2_data . fmt . fmt . pix . colorspace ) ;
Debug ( 4 , " v4l2_data.fmt.fmt.pix.priv = %08x " , v4l2_data . fmt . fmt . pix . priv ) ;
2008-07-21 23:20:52 +08:00
/* Buggy driver paranoia. */
unsigned int min ;
min = v4l2_data . fmt . fmt . pix . width * 2 ;
if ( v4l2_data . fmt . fmt . pix . bytesperline < min )
v4l2_data . fmt . fmt . pix . bytesperline = min ;
min = v4l2_data . fmt . fmt . pix . bytesperline * v4l2_data . fmt . fmt . pix . height ;
if ( v4l2_data . fmt . fmt . pix . sizeimage < min )
v4l2_data . fmt . fmt . pix . sizeimage = min ;
2011-07-01 23:01:24 +08:00
v4l2_jpegcompression jpeg_comp ;
if ( palette = = V4L2_PIX_FMT_JPEG | | palette = = V4L2_PIX_FMT_MJPEG ) {
if ( vidioctl ( vid_fd , VIDIOC_G_JPEGCOMP , & jpeg_comp ) < 0 ) {
2011-10-26 19:28:07 +08:00
if ( errno = = EINVAL ) {
2011-10-30 20:53:46 +08:00
Debug ( 2 , " JPEG compression options are not available " ) ;
2011-10-26 19:28:07 +08:00
} else {
Warning ( " Failed to get JPEG compression options: %s " , strerror ( errno ) ) ;
}
2011-07-01 23:01:24 +08:00
} else {
2011-07-05 23:23:02 +08:00
/* Set flags and quality. MJPEG should not have the huffman tables defined */
if ( palette = = V4L2_PIX_FMT_MJPEG ) {
jpeg_comp . jpeg_markers | = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI ;
} else {
jpeg_comp . jpeg_markers | = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI | V4L2_JPEG_MARKER_DHT ;
}
2011-07-01 23:01:24 +08:00
jpeg_comp . quality = 85 ;
/* Update the JPEG options */
if ( vidioctl ( vid_fd , VIDIOC_S_JPEGCOMP , & jpeg_comp ) < 0 ) {
2011-07-05 23:23:02 +08:00
Warning ( " Failed to set JPEG compression options: %s " , strerror ( errno ) ) ;
2011-07-01 23:01:24 +08:00
} else {
2011-07-05 23:23:02 +08:00
if ( vidioctl ( vid_fd , VIDIOC_G_JPEGCOMP , & jpeg_comp ) < 0 ) {
Debug ( 3 , " Failed to get updated JPEG compression options: %s " , strerror ( errno ) ) ;
} else {
Debug ( 4 , " JPEG quality: %d " , jpeg_comp . quality ) ;
Debug ( 4 , " JPEG markers: %#x " , jpeg_comp . jpeg_markers ) ;
}
2011-07-01 23:01:24 +08:00
}
}
}
2008-07-21 23:20:52 +08:00
Debug ( 3 , " Setting up request buffers " ) ;
2009-02-13 05:33:05 +08:00
2008-07-21 23:20:52 +08:00
memset ( & v4l2_data . reqbufs , 0 , sizeof ( v4l2_data . reqbufs ) ) ;
2014-07-15 00:53:48 +08:00
if ( channel_count > 1 ) {
2014-09-09 03:20:35 +08:00
Debug ( 3 , " Channel count is %d " , channel_count ) ;
2014-07-15 00:53:48 +08:00
if ( v4l_multi_buffer ) {
2009-02-18 05:23:27 +08:00
v4l2_data . reqbufs . count = 2 * channel_count ;
2014-07-15 00:53:48 +08:00
} else {
2009-02-18 05:23:27 +08:00
v4l2_data . reqbufs . count = 1 ;
2014-07-15 00:53:48 +08:00
}
} else {
2009-02-18 05:23:27 +08:00
v4l2_data . reqbufs . count = 8 ;
2014-07-15 00:53:48 +08:00
}
2014-09-09 03:20:35 +08:00
Debug ( 3 , " Request buffers count is %d " , v4l2_data . reqbufs . count ) ;
2014-07-15 00:53:48 +08:00
2008-07-21 23:20:52 +08:00
v4l2_data . reqbufs . type = v4l2_data . fmt . type ;
v4l2_data . reqbufs . memory = V4L2_MEMORY_MMAP ;
if ( vidioctl ( vid_fd , VIDIOC_REQBUFS , & v4l2_data . reqbufs ) < 0 )
{
if ( errno = = EINVAL )
{
Fatal ( " Unable to initialise memory mapping, unsupported in device " ) ;
}
else
{
Fatal ( " Unable to initialise memory mapping: %s " , strerror ( errno ) ) ;
}
}
2003-03-26 19:57:29 +08:00
2014-07-14 04:39:27 +08:00
if ( v4l2_data . reqbufs . count < ( v4l_multi_buffer ? 2 : 1 ) )
2008-07-21 23:20:52 +08:00
Fatal ( " Insufficient buffer memory %d on video device " , v4l2_data . reqbufs . count ) ;
2003-03-26 19:57:29 +08:00
2014-09-09 03:20:35 +08:00
Debug ( 3 , " Setting up data buffers: Channels %d MultiBuffer %d Buffers: %d " , channel_count , v4l_multi_buffer , v4l2_data . reqbufs . count ) ;
2003-03-26 19:57:29 +08:00
2008-07-21 23:20:52 +08:00
v4l2_data . buffers = new V4L2MappedBuffer [ v4l2_data . reqbufs . count ] ;
2009-01-28 23:02:33 +08:00
# if HAVE_LIBSWSCALE
2009-02-18 20:30:43 +08:00
capturePictures = new AVFrame * [ v4l2_data . reqbufs . count ] ;
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBSWSCALE
2013-03-17 07:45:21 +08:00
for ( unsigned int i = 0 ; i < v4l2_data . reqbufs . count ; i + + )
2008-07-21 23:20:52 +08:00
{
struct v4l2_buffer vid_buf ;
2003-03-26 19:57:29 +08:00
2008-07-21 23:20:52 +08:00
memset ( & vid_buf , 0 , sizeof ( vid_buf ) ) ;
//vid_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vid_buf . type = v4l2_data . fmt . type ;
//vid_buf.memory = V4L2_MEMORY_MMAP;
vid_buf . memory = v4l2_data . reqbufs . memory ;
vid_buf . index = i ;
2009-01-27 19:07:24 +08:00
if ( vidioctl ( vid_fd , VIDIOC_QUERYBUF , & vid_buf ) < 0 )
2008-07-21 23:20:52 +08:00
Fatal ( " Unable to query video buffer: %s " , strerror ( errno ) ) ;
v4l2_data . buffers [ i ] . length = vid_buf . length ;
v4l2_data . buffers [ i ] . start = mmap ( NULL , vid_buf . length , PROT_READ | PROT_WRITE , MAP_SHARED , vid_fd , vid_buf . m . offset ) ;
if ( v4l2_data . buffers [ i ] . start = = MAP_FAILED )
Fatal ( " Can't map video buffer %d (%d bytes) to memory: %s(%d) " , i , vid_buf . length , strerror ( errno ) , errno ) ;
2009-01-28 17:48:06 +08:00
2009-01-28 23:02:33 +08:00
# if HAVE_LIBSWSCALE
2015-05-29 23:38:02 +08:00
# if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
capturePictures [ i ] = av_frame_alloc ( ) ;
# else
2011-05-08 21:32:42 +08:00
capturePictures [ i ] = avcodec_alloc_frame ( ) ;
2015-05-29 23:38:02 +08:00
# endif
2011-05-08 21:32:42 +08:00
if ( ! capturePictures [ i ] )
Fatal ( " Could not allocate picture " ) ;
avpicture_fill ( ( AVPicture * ) capturePictures [ i ] , ( uint8_t * ) v4l2_data . buffers [ i ] . start , capturePixFormat , v4l2_data . fmt . fmt . pix . width , v4l2_data . fmt . fmt . pix . height ) ;
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBSWSCALE
2008-07-21 23:20:52 +08:00
}
2009-01-27 19:07:24 +08:00
Debug ( 3 , " Configuring video source " ) ;
if ( vidioctl ( vid_fd , VIDIOC_S_INPUT , & channel ) < 0 )
{
Fatal ( " Failed to set camera source %d: %s " , channel , strerror ( errno ) ) ;
}
struct v4l2_input input ;
v4l2_std_id stdId ;
memset ( & input , 0 , sizeof ( input ) ) ;
if ( vidioctl ( vid_fd , VIDIOC_ENUMINPUT , & input ) < 0 )
{
Fatal ( " Failed to enumerate input %d: %s " , channel , strerror ( errno ) ) ;
}
2009-02-13 05:33:05 +08:00
if ( ( input . std ! = V4L2_STD_UNKNOWN ) & & ( ( input . std & standard ) = = V4L2_STD_UNKNOWN ) )
2009-01-27 19:07:24 +08:00
{
2009-02-13 05:33:05 +08:00
Fatal ( " Device does not support video standard %d " , standard ) ;
2009-01-27 19:07:24 +08:00
}
2009-02-13 05:33:05 +08:00
stdId = standard ;
2009-02-21 02:15:16 +08:00
if ( ( input . std ! = V4L2_STD_UNKNOWN ) & & vidioctl ( vid_fd , VIDIOC_S_STD , & stdId ) < 0 )
2009-01-27 19:07:24 +08:00
{
2009-02-13 05:33:05 +08:00
Fatal ( " Failed to set video standard %d: %s " , standard , strerror ( errno ) ) ;
2009-01-27 19:07:24 +08:00
}
2009-05-13 18:43:49 +08:00
Contrast ( contrast ) ;
Brightness ( brightness ) ;
Hue ( hue ) ;
Colour ( colour ) ;
2008-07-21 23:20:52 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
Debug ( 3 , " Configuring picture attributes " ) ;
struct video_picture vid_pic ;
memset ( & vid_pic , 0 , sizeof ( vid_pic ) ) ;
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
Fatal ( " Failed to get picture attributes: %s " , strerror ( errno ) ) ;
Debug ( 4 , " Old P:%d " , vid_pic . palette ) ;
Debug ( 4 , " Old D:%d " , vid_pic . depth ) ;
Debug ( 4 , " Old B:%d " , vid_pic . brightness ) ;
Debug ( 4 , " Old h:%d " , vid_pic . hue ) ;
Debug ( 4 , " Old Cl:%d " , vid_pic . colour ) ;
Debug ( 4 , " Old Cn:%d " , vid_pic . contrast ) ;
switch ( vid_pic . palette = palette )
{
2011-04-29 22:26:50 +08:00
case VIDEO_PALETTE_RGB32 :
{
vid_pic . depth = 32 ;
break ;
}
case VIDEO_PALETTE_RGB24 :
{
vid_pic . depth = 24 ;
break ;
}
2008-07-21 23:20:52 +08:00
case VIDEO_PALETTE_GREY :
{
vid_pic . depth = 8 ;
break ;
2011-04-29 22:26:50 +08:00
}
2008-07-21 23:20:52 +08:00
case VIDEO_PALETTE_RGB565 :
case VIDEO_PALETTE_YUYV :
case VIDEO_PALETTE_YUV422 :
case VIDEO_PALETTE_YUV420P :
case VIDEO_PALETTE_YUV422P :
2011-04-29 22:26:50 +08:00
default :
2008-07-21 23:20:52 +08:00
{
vid_pic . depth = 16 ;
break ;
}
}
if ( brightness > = 0 ) vid_pic . brightness = brightness ;
if ( hue > = 0 ) vid_pic . hue = hue ;
if ( colour > = 0 ) vid_pic . colour = colour ;
if ( contrast > = 0 ) vid_pic . contrast = contrast ;
if ( ioctl ( vid_fd , VIDIOCSPICT , & vid_pic ) < 0 )
{
Error ( " Failed to set picture attributes: %s " , strerror ( errno ) ) ;
if ( config . strict_video_config )
exit ( - 1 ) ;
}
Debug ( 3 , " Configuring window attributes " ) ;
struct video_window vid_win ;
memset ( & vid_win , 0 , sizeof ( vid_win ) ) ;
if ( ioctl ( vid_fd , VIDIOCGWIN , & vid_win ) < 0 )
{
Error ( " Failed to get window attributes: %s " , strerror ( errno ) ) ;
exit ( - 1 ) ;
}
Debug ( 4 , " Old X:%d " , vid_win . x ) ;
Debug ( 4 , " Old Y:%d " , vid_win . y ) ;
Debug ( 4 , " Old W:%d " , vid_win . width ) ;
Debug ( 4 , " Old H:%d " , vid_win . height ) ;
vid_win . x = 0 ;
vid_win . y = 0 ;
vid_win . width = width ;
vid_win . height = height ;
vid_win . flags & = ~ VIDEO_WINDOW_INTERLACE ;
if ( ioctl ( vid_fd , VIDIOCSWIN , & vid_win ) < 0 )
{
Error ( " Failed to set window attributes: %s " , strerror ( errno ) ) ;
if ( config . strict_video_config )
exit ( - 1 ) ;
}
2011-01-21 02:49:42 +08:00
Info ( " vid_win.width = %08x " , vid_win . width ) ;
Info ( " vid_win.height = %08x " , vid_win . height ) ;
Info ( " vid_win.flags = %08x " , vid_win . flags ) ;
2008-07-21 23:20:52 +08:00
Debug ( 3 , " Setting up request buffers " ) ;
2009-01-28 17:48:06 +08:00
if ( ioctl ( vid_fd , VIDIOCGMBUF , & v4l1_data . frames ) < 0 )
Fatal ( " Failed to setup memory: %s " , strerror ( errno ) ) ;
2014-07-14 04:39:27 +08:00
if ( channel_count > 1 & & ! v4l_multi_buffer )
2009-02-18 05:23:27 +08:00
v4l1_data . frames . frames = 1 ;
2008-07-21 23:20:52 +08:00
v4l1_data . buffers = new video_mmap [ v4l1_data . frames . frames ] ;
Debug ( 4 , " vmb.frames = %d " , v4l1_data . frames . frames ) ;
Debug ( 4 , " vmb.size = %d " , v4l1_data . frames . size ) ;
2009-01-28 17:48:06 +08:00
Debug ( 3 , " Setting up %d frame buffers " , v4l1_data . frames . frames ) ;
2009-02-13 05:33:05 +08:00
v4l1_data . bufptr = ( unsigned char * ) mmap ( 0 , v4l1_data . frames . size , PROT_READ | PROT_WRITE , MAP_SHARED , vid_fd , 0 ) ;
if ( v4l1_data . bufptr = = MAP_FAILED )
2009-01-28 17:48:06 +08:00
Fatal ( " Could not mmap video: %s " , strerror ( errno ) ) ;
2009-01-28 23:02:33 +08:00
# if HAVE_LIBSWSCALE
2009-02-18 20:30:43 +08:00
capturePictures = new AVFrame * [ v4l1_data . frames . frames ] ;
2009-01-28 17:48:06 +08:00
for ( int i = 0 ; i < v4l1_data . frames . frames ; i + + )
2008-07-21 23:20:52 +08:00
{
v4l1_data . buffers [ i ] . frame = i ;
v4l1_data . buffers [ i ] . width = width ;
v4l1_data . buffers [ i ] . height = height ;
v4l1_data . buffers [ i ] . format = palette ;
2015-05-29 23:38:02 +08:00
# if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
capturePictures [ i ] = av_frame_alloc ( ) ;
# else
2011-05-08 21:32:42 +08:00
capturePictures [ i ] = avcodec_alloc_frame ( ) ;
2015-05-29 23:38:02 +08:00
# endif
2011-05-08 21:32:42 +08:00
if ( ! capturePictures [ i ] )
Fatal ( " Could not allocate picture " ) ;
avpicture_fill ( ( AVPicture * ) capturePictures [ i ] , ( unsigned char * ) v4l1_data . bufptr + v4l1_data . frames . offsets [ i ] , capturePixFormat , width , height ) ;
2008-07-21 23:20:52 +08:00
}
2009-01-28 23:02:33 +08:00
# endif // HAVE_LIBSWSCALE
2008-07-21 23:20:52 +08:00
Debug ( 3 , " Configuring video source " ) ;
struct video_channel vid_src ;
memset ( & vid_src , 0 , sizeof ( vid_src ) ) ;
vid_src . channel = channel ;
if ( ioctl ( vid_fd , VIDIOCGCHAN , & vid_src ) < 0 )
2009-01-28 17:48:06 +08:00
Fatal ( " Failed to get camera source: %s " , strerror ( errno ) ) ;
2008-07-21 23:20:52 +08:00
Debug ( 4 , " Old C:%d " , vid_src . channel ) ;
Debug ( 4 , " Old F:%d " , vid_src . norm ) ;
Debug ( 4 , " Old Fl:%x " , vid_src . flags ) ;
Debug ( 4 , " Old T:%d " , vid_src . type ) ;
2009-02-13 05:33:05 +08:00
vid_src . norm = standard ;
2008-07-21 23:20:52 +08:00
vid_src . flags = 0 ;
vid_src . type = VIDEO_TYPE_CAMERA ;
if ( ioctl ( vid_fd , VIDIOCSCHAN , & vid_src ) < 0 )
{
Error ( " Failed to set camera source %d: %s " , channel , strerror ( errno ) ) ;
if ( config . strict_video_config )
exit ( - 1 ) ;
}
if ( ioctl ( vid_fd , VIDIOCGWIN , & vid_win ) < 0 )
2009-01-28 17:48:06 +08:00
Fatal ( " Failed to get window data: %s " , strerror ( errno ) ) ;
2011-01-21 02:49:42 +08:00
Info ( " vid_win.width = %08x " , vid_win . width ) ;
Info ( " vid_win.height = %08x " , vid_win . height ) ;
Info ( " vid_win.flags = %08x " , vid_win . flags ) ;
2008-07-21 23:20:52 +08:00
Debug ( 4 , " New X:%d " , vid_win . x ) ;
Debug ( 4 , " New Y:%d " , vid_win . y ) ;
Debug ( 4 , " New W:%d " , vid_win . width ) ;
Debug ( 4 , " New H:%d " , vid_win . height ) ;
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
2009-01-28 17:48:06 +08:00
Fatal ( " Failed to get window data: %s " , strerror ( errno ) ) ;
2008-07-21 23:20:52 +08:00
Debug ( 4 , " New P:%d " , vid_pic . palette ) ;
Debug ( 4 , " New D:%d " , vid_pic . depth ) ;
Debug ( 4 , " New B:%d " , vid_pic . brightness ) ;
Debug ( 4 , " New h:%d " , vid_pic . hue ) ;
Debug ( 4 , " New Cl:%d " , vid_pic . colour ) ;
Debug ( 4 , " New Cn:%d " , vid_pic . contrast ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2003-03-26 19:57:29 +08:00
}
void LocalCamera : : Terminate ( )
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
Debug ( 3 , " Terminating video stream " ) ;
//enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2013-03-17 07:45:21 +08:00
// enum v4l2_buf_type type = v4l2_data.fmt.type;
2013-04-30 01:29:51 +08:00
enum v4l2_buf_type type = ( v4l2_buf_type ) v4l2_data . fmt . type ;
2008-07-21 23:20:52 +08:00
if ( vidioctl ( vid_fd , VIDIOC_STREAMOFF , & type ) < 0 )
Error ( " Failed to stop capture stream: %s " , strerror ( errno ) ) ;
Debug ( 3 , " Unmapping video buffers " ) ;
2013-03-17 07:45:21 +08:00
for ( unsigned int i = 0 ; i < v4l2_data . reqbufs . count ; i + + ) {
2011-05-05 17:52:00 +08:00
# if HAVE_LIBSWSCALE
/* Free capture pictures */
2015-11-03 08:58:23 +08:00
av_frame_free ( & capturePictures [ i ] ) ;
2011-05-05 17:52:00 +08:00
capturePictures [ i ] = NULL ;
# endif
2008-07-21 23:20:52 +08:00
if ( munmap ( v4l2_data . buffers [ i ] . start , v4l2_data . buffers [ i ] . length ) < 0 )
Error ( " Failed to munmap buffer %d: %s " , i , strerror ( errno ) ) ;
2011-05-05 17:52:00 +08:00
}
2008-07-21 23:20:52 +08:00
}
else
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
2011-05-05 17:52:00 +08:00
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
2011-05-05 17:52:00 +08:00
# if HAVE_LIBSWSCALE
2013-09-17 15:28:59 +08:00
for ( int i = 0 ; i < v4l1_data . frames . frames ; i + + ) {
2011-05-05 17:52:00 +08:00
/* Free capture pictures */
2015-11-03 08:58:23 +08:00
av_frame_free ( & capturePictures [ i ] ) ;
2011-05-05 17:52:00 +08:00
capturePictures [ i ] = NULL ;
}
# endif
2008-07-21 23:20:52 +08:00
Debug ( 3 , " Unmapping video buffers " ) ;
2009-02-13 05:33:05 +08:00
if ( munmap ( ( char * ) v4l1_data . bufptr , v4l1_data . frames . size ) < 0 )
2008-07-21 23:20:52 +08:00
Error ( " Failed to munmap buffers: %s " , strerror ( errno ) ) ;
2003-03-26 19:57:29 +08:00
2008-07-21 23:20:52 +08:00
delete [ ] v4l1_data . buffers ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2003-03-26 19:57:29 +08:00
2008-07-21 23:20:52 +08:00
close ( vid_fd ) ;
2011-05-05 17:52:00 +08:00
2003-03-26 19:57:29 +08:00
}
2011-07-02 20:32:16 +08:00
uint32_t LocalCamera : : AutoSelectFormat ( int p_colours ) {
/* Automatic format selection */
uint32_t selected_palette = 0 ;
# if ZM_HAS_V4L2
char fmt_desc [ 64 ] [ 32 ] ;
uint32_t fmt_fcc [ 64 ] ;
v4l2_fmtdesc fmtinfo ;
unsigned int nIndex = 0 ;
2013-03-17 07:45:21 +08:00
//int nRet = 0; // compiler say it isn't used
2011-07-02 20:32:16 +08:00
int enum_fd ;
/* Open the device */
if ( ( enum_fd = open ( device . c_str ( ) , O_RDWR , 0 ) ) < 0 ) {
2011-07-05 23:23:02 +08:00
Error ( " Automatic format selection failed to open video device %s: %s " , device . c_str ( ) , strerror ( errno ) ) ;
2011-07-02 20:32:16 +08:00
return selected_palette ;
}
/* Enumerate available formats */
memset ( & fmtinfo , 0 , sizeof ( fmtinfo ) ) ;
fmtinfo . index = nIndex ;
fmtinfo . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2015-02-11 00:11:54 +08:00
// FIXME This will crash if there are more than 64 formats.
2011-07-02 20:32:16 +08:00
while ( vidioctl ( enum_fd , VIDIOC_ENUM_FMT , & fmtinfo ) > = 0 ) {
/* Got a format. Copy it to the array */
strcpy ( fmt_desc [ nIndex ] , ( const char * ) ( fmtinfo . description ) ) ;
fmt_fcc [ nIndex ] = fmtinfo . pixelformat ;
Debug ( 6 , " Got format: %s (%c%c%c%c) at index %d " , fmt_desc [ nIndex ] , fmt_fcc [ nIndex ] & 0xff , ( fmt_fcc [ nIndex ] > > 8 ) & 0xff , ( fmt_fcc [ nIndex ] > > 16 ) & 0xff , ( fmt_fcc [ nIndex ] > > 24 ) & 0xff , nIndex ) ;
/* Proceed to the next index */
memset ( & fmtinfo , 0 , sizeof ( fmtinfo ) ) ;
fmtinfo . index = + + nIndex ;
fmtinfo . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
}
/* Select format */
int nIndexUsed = - 1 ;
2015-02-11 00:11:54 +08:00
unsigned int n_preferedformats = 0 ;
2011-07-02 20:32:16 +08:00
const uint32_t * preferedformats ;
if ( p_colours = = ZM_COLOUR_RGB32 ) {
/* 32bit */
preferedformats = prefered_rgb32_formats ;
n_preferedformats = sizeof ( prefered_rgb32_formats ) / sizeof ( uint32_t ) ;
} else if ( p_colours = = ZM_COLOUR_GRAY8 ) {
/* Grayscale */
preferedformats = prefered_gray8_formats ;
n_preferedformats = sizeof ( prefered_gray8_formats ) / sizeof ( uint32_t ) ;
} else {
/* Assume 24bit */
preferedformats = prefered_rgb24_formats ;
n_preferedformats = sizeof ( prefered_rgb24_formats ) / sizeof ( uint32_t ) ;
}
2015-02-11 00:11:54 +08:00
for ( unsigned int i = 0 ; i < n_preferedformats & & nIndexUsed < 0 ; i + + ) {
2011-07-02 20:32:16 +08:00
for ( unsigned int j = 0 ; j < nIndex ; j + + ) {
if ( preferedformats [ i ] = = fmt_fcc [ j ] ) {
2015-02-11 00:11:54 +08:00
Debug ( 6 , " Choosing format: %s (%c%c%c%c) at index %d " , fmt_desc [ j ] , fmt_fcc [ j ] & 0xff , ( fmt_fcc [ j ] > > 8 ) & 0xff , ( fmt_fcc [ j ] > > 16 ) & 0xff , ( fmt_fcc [ j ] > > 24 ) & 0xff , j ) ;
2011-07-02 20:32:16 +08:00
/* Found a format! */
nIndexUsed = j ;
break ;
2015-02-11 00:11:54 +08:00
} else {
Debug ( 6 , " No match for format: %s (%c%c%c%c) at index %d " , fmt_desc [ j ] , fmt_fcc [ j ] & 0xff , ( fmt_fcc [ j ] > > 8 ) & 0xff , ( fmt_fcc [ j ] > > 16 ) & 0xff , ( fmt_fcc [ j ] > > 24 ) & 0xff , j ) ;
2011-07-02 20:32:16 +08:00
}
}
}
/* Have we found a match? */
if ( nIndexUsed > = 0 ) {
/* Found a match */
selected_palette = fmt_fcc [ nIndexUsed ] ;
strcpy ( palette_desc , fmt_desc [ nIndexUsed ] ) ;
}
/* Close the device */
close ( enum_fd ) ;
# endif /* ZM_HAS_V4L2 */
return selected_palette ;
2003-03-26 19:57:29 +08:00
}
2011-07-02 20:32:16 +08:00
2009-03-31 20:57:34 +08:00
# define capString(test,prefix,yesString,noString,capability) \
( test ) ? ( prefix yesString " " capability " \n " ) : ( prefix noString " " capability " \n " )
bool LocalCamera : : GetCurrentSettings ( const char * device , char * output , int version , bool verbose )
2003-03-26 19:57:29 +08:00
{
output [ 0 ] = 0 ;
2009-03-31 20:57:34 +08:00
char queryDevice [ PATH_MAX ] = " " ;
int devIndex = 0 ;
do
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
if ( device )
strcpy ( queryDevice , device ) ;
else
sprintf ( queryDevice , " /dev/video%d " , devIndex ) ;
if ( ( vid_fd = open ( queryDevice , O_RDWR ) ) < = 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
if ( device )
{
Error ( " Failed to open video device %s: %s " , queryDevice , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output + strlen ( output ) , " Error, failed to open video device %s: %s \n " , queryDevice , strerror ( errno ) ) ;
else
sprintf ( output + strlen ( output ) , " error%d \n " , errno ) ;
return ( false ) ;
}
2009-03-30 23:27:15 +08:00
else
2009-03-31 20:57:34 +08:00
{
return ( true ) ;
}
2009-03-30 23:27:15 +08:00
}
if ( verbose )
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " Video Device: %s \n " , queryDevice ) ;
2009-03-30 23:27:15 +08:00
else
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " d:%s| " , queryDevice ) ;
2004-03-16 23:40:10 +08:00
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-03-31 20:57:34 +08:00
if ( version = = 2 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
struct v4l2_capability vid_cap ;
if ( vidioctl ( vid_fd , VIDIOC_QUERYCAP , & vid_cap ) < 0 )
{
Error ( " Failed to query video device: %s " , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output , " Error, failed to query video capabilities %s: %s \n " , queryDevice , strerror ( errno ) ) ;
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
2003-03-26 19:57:29 +08:00
2009-03-31 20:57:34 +08:00
if ( verbose )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " General Capabilities \n " ) ;
sprintf ( output + strlen ( output ) , " Driver: %s \n " , vid_cap . driver ) ;
sprintf ( output + strlen ( output ) , " Card: %s \n " , vid_cap . card ) ;
sprintf ( output + strlen ( output ) , " Bus: %s \n " , vid_cap . bus_info ) ;
sprintf ( output + strlen ( output ) , " Version: %u.%u.%u \n " , ( vid_cap . version > > 16 ) & 0xff , ( vid_cap . version > > 8 ) & 0xff , vid_cap . version & 0xff ) ;
sprintf ( output + strlen ( output ) , " Type: 0x%x \n %s%s%s%s%s%s%s%s%s%s%s%s%s%s " , vid_cap . capabilities ,
capString ( vid_cap . capabilities & V4L2_CAP_VIDEO_CAPTURE , " " , " Supports " , " Does not support " , " video capture (X) " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_VIDEO_OUTPUT , " " , " Supports " , " Does not support " , " video output " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_VIDEO_OVERLAY , " " , " Supports " , " Does not support " , " frame buffer overlay " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_VBI_CAPTURE , " " , " Supports " , " Does not support " , " VBI capture " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_VBI_OUTPUT , " " , " Supports " , " Does not support " , " VBI output " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_SLICED_VBI_CAPTURE , " " , " Supports " , " Does not support " , " sliced VBI capture " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_SLICED_VBI_OUTPUT , " " , " Supports " , " Does not support " , " sliced VBI output " ) ,
2009-03-31 22:09:53 +08:00
# ifdef V4L2_CAP_VIDEO_OUTPUT_OVERLAY
2009-03-31 20:57:34 +08:00
capString ( vid_cap . capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY , " " , " Supports " , " Does not support " , " video output overlay " ) ,
2009-03-31 22:09:53 +08:00
# else // V4L2_CAP_VIDEO_OUTPUT_OVERLAY
" " ,
# endif // V4L2_CAP_VIDEO_OUTPUT_OVERLAY
2009-03-31 20:57:34 +08:00
capString ( vid_cap . capabilities & V4L2_CAP_TUNER , " " , " Has " , " Does not have " , " tuner " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_AUDIO , " " , " Has " , " Does not have " , " audio in and/or out " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_RADIO , " " , " Has " , " Does not have " , " radio " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_READWRITE , " " , " Supports " , " Does not support " , " read/write i/o (X) " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_ASYNCIO , " " , " Supports " , " Does not support " , " async i/o " ) ,
capString ( vid_cap . capabilities & V4L2_CAP_STREAMING , " " , " Supports " , " Does not support " , " streaming i/o (X) " )
) ;
}
else
{
sprintf ( output + strlen ( output ) , " D:%s| " , vid_cap . driver ) ;
sprintf ( output + strlen ( output ) , " C:%s| " , vid_cap . card ) ;
sprintf ( output + strlen ( output ) , " B:%s| " , vid_cap . bus_info ) ;
sprintf ( output + strlen ( output ) , " V:%u.%u.%u| " , ( vid_cap . version > > 16 ) & 0xff , ( vid_cap . version > > 8 ) & 0xff , vid_cap . version & 0xff ) ;
sprintf ( output + strlen ( output ) , " T:0x%x| " , vid_cap . capabilities ) ;
}
if ( verbose )
sprintf ( output + strlen ( output ) , " Standards: \n " ) ;
else
sprintf ( output + strlen ( output ) , " S: " ) ;
struct v4l2_standard standard ;
int standardIndex = 0 ;
do
{
memset ( & standard , 0 , sizeof ( standard ) ) ;
standard . index = standardIndex ;
if ( vidioctl ( vid_fd , VIDIOC_ENUMSTD , & standard ) < 0 )
2009-03-30 23:27:15 +08:00
{
2015-02-11 00:53:50 +08:00
if ( errno = = EINVAL | | errno = = ENODATA | | errno = = ENOTTY )
2009-03-31 20:57:34 +08:00
{
2015-02-11 00:53:50 +08:00
Debug ( 6 , " Done enumerating standard %d: %d %s " , standard . index , errno , strerror ( errno ) ) ;
2009-03-31 20:57:34 +08:00
standardIndex = - 1 ;
break ;
}
else
{
2015-02-11 00:53:50 +08:00
Error ( " Failed to enumerate standard %d: %d %s " , standard . index , errno , strerror ( errno ) ) ;
2009-03-31 20:57:34 +08:00
if ( verbose )
2015-02-11 00:53:50 +08:00
sprintf ( output , " Error, failed to enumerate standard %d: %d %s \n " , standard . index , errno , strerror ( errno ) ) ;
2009-03-31 20:57:34 +08:00
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
if ( verbose )
sprintf ( output + strlen ( output ) , " %s \n " , standard . name ) ;
2009-03-30 23:27:15 +08:00
else
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " %s/ " , standard . name ) ;
}
while ( standardIndex + + > = 0 ) ;
2010-03-01 01:38:30 +08:00
if ( ! verbose & & output [ strlen ( output ) - 1 ] = = ' / ' )
2009-03-31 20:57:34 +08:00
output [ strlen ( output ) - 1 ] = ' | ' ;
if ( verbose )
sprintf ( output + strlen ( output ) , " Formats: \n " ) ;
else
sprintf ( output + strlen ( output ) , " F: " ) ;
struct v4l2_fmtdesc format ;
int formatIndex = 0 ;
do
{
memset ( & format , 0 , sizeof ( format ) ) ;
format . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
format . index = formatIndex ;
if ( vidioctl ( vid_fd , VIDIOC_ENUM_FMT , & format ) < 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
if ( errno = = EINVAL )
{
formatIndex = - 1 ;
break ;
}
2009-03-30 23:27:15 +08:00
else
2009-03-31 20:57:34 +08:00
{
Error ( " Failed to enumerate format %d: %s " , format . index , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output , " Error, failed to enumerate format %d: %s \n " , format . index , strerror ( errno ) ) ;
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
if ( verbose )
sprintf ( output + strlen ( output ) , " %s (%c%c%c%c) \n " , format . description , format . pixelformat & 0xff , ( format . pixelformat > > 8 ) & 0xff , ( format . pixelformat > > 16 ) & 0xff , ( format . pixelformat > > 24 ) & 0xff ) ;
else
sprintf ( output + strlen ( output ) , " %c%c%c%c/ " , format . pixelformat & 0xff , ( format . pixelformat > > 8 ) & 0xff , ( format . pixelformat > > 16 ) & 0xff , ( format . pixelformat > > 24 ) & 0xff ) ;
}
while ( formatIndex + + > = 0 ) ;
if ( ! verbose )
output [ strlen ( output ) - 1 ] = ' | ' ;
2009-03-30 23:27:15 +08:00
2011-07-16 19:27:53 +08:00
if ( verbose )
sprintf ( output + strlen ( output ) , " Crop Capabilities \n " ) ;
2011-06-08 04:14:01 +08:00
struct v4l2_cropcap cropcap ;
memset ( & cropcap , 0 , sizeof ( cropcap ) ) ;
cropcap . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
if ( vidioctl ( vid_fd , VIDIOC_CROPCAP , & cropcap ) < 0 )
{
if ( errno ! = EINVAL ) {
/* Failed querying crop capability, write error to the log and continue as if crop is not supported */
Error ( " Failed to query crop capabilities: %s " , strerror ( errno ) ) ;
}
if ( verbose ) {
2011-07-06 23:39:16 +08:00
sprintf ( output + strlen ( output ) , " Cropping is not supported \n " ) ;
2011-06-08 04:14:01 +08:00
} else {
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
sprintf ( output + strlen ( output ) , " B:%dx%d| " , 0 , 0 ) ;
}
} else {
struct v4l2_crop crop ;
memset ( & crop , 0 , sizeof ( crop ) ) ;
crop . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
if ( vidioctl ( vid_fd , VIDIOC_G_CROP , & crop ) < 0 )
{
if ( errno ! = EINVAL )
{
/* Failed querying crop sizes, write error to the log and continue as if crop is not supported */
Error ( " Failed to query crop: %s " , strerror ( errno ) ) ;
}
if ( verbose ) {
2011-07-06 23:39:16 +08:00
sprintf ( output + strlen ( output ) , " Cropping is not supported \n " ) ;
2011-06-08 04:14:01 +08:00
} else {
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
sprintf ( output + strlen ( output ) , " B:%dx%d| " , 0 , 0 ) ;
}
} else {
/* Cropping supported */
if ( verbose ) {
2011-07-16 19:27:53 +08:00
sprintf ( output + strlen ( output ) , " Bounds: %d x %d \n " , cropcap . bounds . width , cropcap . bounds . height ) ;
sprintf ( output + strlen ( output ) , " Default: %d x %d \n " , cropcap . defrect . width , cropcap . defrect . height ) ;
sprintf ( output + strlen ( output ) , " Current: %d x %d \n " , crop . c . width , crop . c . height ) ;
2011-06-08 04:14:01 +08:00
} else {
sprintf ( output + strlen ( output ) , " B:%dx%d| " , cropcap . bounds . width , cropcap . bounds . height ) ;
}
}
} /* Crop code */
2009-03-31 20:57:34 +08:00
struct v4l2_input input ;
int inputIndex = 0 ;
do
{
memset ( & input , 0 , sizeof ( input ) ) ;
input . index = inputIndex ;
if ( vidioctl ( vid_fd , VIDIOC_ENUMINPUT , & input ) < 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
if ( errno = = EINVAL )
{
break ;
}
2009-03-30 23:27:15 +08:00
else
2009-03-31 20:57:34 +08:00
{
Error ( " Failed to enumerate input %d: %s " , input . index , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output , " Error, failed to enumerate input %d: %s \n " , input . index , strerror ( errno ) ) ;
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
2009-03-30 23:27:15 +08:00
}
}
2009-03-31 20:57:34 +08:00
while ( inputIndex + + > = 0 ) ;
2009-03-30 23:27:15 +08:00
if ( verbose )
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " Inputs: %d \n " , inputIndex ) ;
2009-03-30 23:27:15 +08:00
else
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " I:%d| " , inputIndex ) ;
2009-03-30 23:27:15 +08:00
2009-03-31 20:57:34 +08:00
inputIndex = 0 ;
do
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
memset ( & input , 0 , sizeof ( input ) ) ;
input . index = inputIndex ;
if ( vidioctl ( vid_fd , VIDIOC_ENUMINPUT , & input ) < 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
if ( errno = = EINVAL )
{
inputIndex = - 1 ;
break ;
}
else
{
Error ( " Failed to enumerate input %d: %s " , input . index , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output , " Error, failed to enumerate input %d: %s \n " , input . index , strerror ( errno ) ) ;
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
if ( vidioctl ( vid_fd , VIDIOC_S_INPUT , & input . index ) < 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
Error ( " Failed to set video input %d: %s " , input . index , strerror ( errno ) ) ;
2009-03-30 23:27:15 +08:00
if ( verbose )
2009-03-31 20:57:34 +08:00
sprintf ( output , " Error, failed to switch to input %d: %s \n " , input . index , strerror ( errno ) ) ;
2009-03-30 23:27:15 +08:00
else
sprintf ( output , " error%d \n " , errno ) ;
2009-03-31 20:57:34 +08:00
return ( false ) ;
}
if ( verbose )
{
sprintf ( output + strlen ( output ) , " Input %d \n " , input . index ) ;
sprintf ( output + strlen ( output ) , " Name: %s \n " , input . name ) ;
sprintf ( output + strlen ( output ) , " Type: %s \n " , input . type = = V4L2_INPUT_TYPE_TUNER ? " Tuner " : ( input . type = = V4L2_INPUT_TYPE_CAMERA ? " Camera " : " Unknown " ) ) ;
sprintf ( output + strlen ( output ) , " Audioset: %08x \n " , input . audioset ) ;
sprintf ( output + strlen ( output ) , " Standards: 0x%llx \n " , input . std ) ;
}
else
{
sprintf ( output + strlen ( output ) , " i%d:%s| " , input . index , input . name ) ;
sprintf ( output + strlen ( output ) , " i%dT:%s| " , input . index , input . type = = V4L2_INPUT_TYPE_TUNER ? " Tuner " : ( input . type = = V4L2_INPUT_TYPE_CAMERA ? " Camera " : " Unknown " ) ) ;
sprintf ( output + strlen ( output ) , " i%dS:%llx| " , input . index , input . std ) ;
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
if ( verbose )
{
sprintf ( output + strlen ( output ) , " %s " , capString ( input . status & V4L2_IN_ST_NO_POWER , " Power " , " off " , " on " , " (X) " ) ) ;
sprintf ( output + strlen ( output ) , " %s " , capString ( input . status & V4L2_IN_ST_NO_SIGNAL , " Signal " , " not detected " , " detected " , " (X) " ) ) ;
sprintf ( output + strlen ( output ) , " %s " , capString ( input . status & V4L2_IN_ST_NO_COLOR , " Colour Signal " , " not detected " , " detected " , " " ) ) ;
sprintf ( output + strlen ( output ) , " %s " , capString ( input . status & V4L2_IN_ST_NO_H_LOCK , " Horizontal Lock " , " not detected " , " detected " , " " ) ) ;
}
else
{
sprintf ( output + strlen ( output ) , " i%dSP:%d| " , input . index , input . status & V4L2_IN_ST_NO_POWER ? 0 : 1 ) ;
sprintf ( output + strlen ( output ) , " i%dSS:%d| " , input . index , input . status & V4L2_IN_ST_NO_SIGNAL ? 0 : 1 ) ;
sprintf ( output + strlen ( output ) , " i%dSC:%d| " , input . index , input . status & V4L2_IN_ST_NO_COLOR ? 0 : 1 ) ;
sprintf ( output + strlen ( output ) , " i%dHP:%d| " , input . index , input . status & V4L2_IN_ST_NO_H_LOCK ? 0 : 1 ) ;
}
}
while ( inputIndex + + > = 0 ) ;
if ( ! verbose )
output [ strlen ( output ) - 1 ] = ' \n ' ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
if ( version = = 1 )
2009-03-31 20:57:34 +08:00
{
struct video_capability vid_cap ;
2011-04-29 22:26:50 +08:00
memset ( & vid_cap , 0 , sizeof ( video_capability ) ) ;
2009-03-31 20:57:34 +08:00
if ( ioctl ( vid_fd , VIDIOCGCAP , & vid_cap ) < 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
Error ( " Failed to get video capabilities: %s " , strerror ( errno ) ) ;
2009-03-30 23:27:15 +08:00
if ( verbose )
2009-03-31 20:57:34 +08:00
sprintf ( output , " Error, failed to get video capabilities %s: %s \n " , queryDevice , strerror ( errno ) ) ;
2009-03-30 23:27:15 +08:00
else
sprintf ( output , " error%d \n " , errno ) ;
2009-03-31 20:57:34 +08:00
return ( false ) ;
2009-03-30 23:27:15 +08:00
}
if ( verbose )
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " Video Capabilities \n " ) ;
sprintf ( output + strlen ( output ) , " Name: %s \n " , vid_cap . name ) ;
sprintf ( output + strlen ( output ) , " Type: %d \n %s%s%s%s%s%s%s%s%s%s%s%s%s%s " , vid_cap . type ,
vid_cap . type & VID_TYPE_CAPTURE ? " Can capture \n " : " " ,
vid_cap . type & VID_TYPE_TUNER ? " Can tune \n " : " " ,
vid_cap . type & VID_TYPE_TELETEXT ? " Does teletext \n " : " " ,
vid_cap . type & VID_TYPE_OVERLAY ? " Overlay onto frame buffer \n " : " " ,
vid_cap . type & VID_TYPE_CHROMAKEY ? " Overlay by chromakey \n " : " " ,
vid_cap . type & VID_TYPE_CLIPPING ? " Can clip \n " : " " ,
vid_cap . type & VID_TYPE_FRAMERAM ? " Uses the frame buffer memory \n " : " " ,
vid_cap . type & VID_TYPE_SCALES ? " Scalable \n " : " " ,
vid_cap . type & VID_TYPE_MONOCHROME ? " Monochrome only \n " : " " ,
vid_cap . type & VID_TYPE_SUBCAPTURE ? " Can capture subareas of the image \n " : " " ,
vid_cap . type & VID_TYPE_MPEG_DECODER ? " Can decode MPEG streams \n " : " " ,
vid_cap . type & VID_TYPE_MPEG_ENCODER ? " Can encode MPEG streams \n " : " " ,
vid_cap . type & VID_TYPE_MJPEG_DECODER ? " Can decode MJPEG streams \n " : " " ,
vid_cap . type & VID_TYPE_MJPEG_ENCODER ? " Can encode MJPEG streams \n " : " "
) ;
sprintf ( output + strlen ( output ) , " Video Channels: %d \n " , vid_cap . channels ) ;
sprintf ( output + strlen ( output ) , " Audio Channels: %d \n " , vid_cap . audios ) ;
sprintf ( output + strlen ( output ) , " Maximum Width: %d \n " , vid_cap . maxwidth ) ;
sprintf ( output + strlen ( output ) , " Maximum Height: %d \n " , vid_cap . maxheight ) ;
sprintf ( output + strlen ( output ) , " Minimum Width: %d \n " , vid_cap . minwidth ) ;
sprintf ( output + strlen ( output ) , " Minimum Height: %d \n " , vid_cap . minheight ) ;
2009-03-30 23:27:15 +08:00
}
else
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " N:%s| " , vid_cap . name ) ;
sprintf ( output + strlen ( output ) , " T:%d| " , vid_cap . type ) ;
sprintf ( output + strlen ( output ) , " nC:%d| " , vid_cap . channels ) ;
sprintf ( output + strlen ( output ) , " nA:%d| " , vid_cap . audios ) ;
sprintf ( output + strlen ( output ) , " mxW:%d| " , vid_cap . maxwidth ) ;
sprintf ( output + strlen ( output ) , " mxH:%d| " , vid_cap . maxheight ) ;
sprintf ( output + strlen ( output ) , " mnW:%d| " , vid_cap . minwidth ) ;
sprintf ( output + strlen ( output ) , " mnH:%d| " , vid_cap . minheight ) ;
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
struct video_window vid_win ;
2011-04-29 22:26:50 +08:00
memset ( & vid_win , 0 , sizeof ( video_window ) ) ;
2009-03-31 20:57:34 +08:00
if ( ioctl ( vid_fd , VIDIOCGWIN , & vid_win ) < 0 )
{
Error ( " Failed to get window attributes: %s " , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output , " Error, failed to get window attributes: %s \n " , strerror ( errno ) ) ;
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
2009-03-30 23:27:15 +08:00
if ( verbose )
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " Window Attributes \n " ) ;
sprintf ( output + strlen ( output ) , " X Offset: %d \n " , vid_win . x ) ;
sprintf ( output + strlen ( output ) , " Y Offset: %d \n " , vid_win . y ) ;
sprintf ( output + strlen ( output ) , " Width: %d \n " , vid_win . width ) ;
sprintf ( output + strlen ( output ) , " Height: %d \n " , vid_win . height ) ;
2009-03-30 23:27:15 +08:00
}
else
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " X:%d| " , vid_win . x ) ;
sprintf ( output + strlen ( output ) , " Y:%d| " , vid_win . y ) ;
sprintf ( output + strlen ( output ) , " W:%d| " , vid_win . width ) ;
sprintf ( output + strlen ( output ) , " H:%d| " , vid_win . height ) ;
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
struct video_picture vid_pic ;
2011-04-29 22:26:50 +08:00
memset ( & vid_cap , 0 , sizeof ( video_picture ) ) ;
2009-03-31 20:57:34 +08:00
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
2009-03-30 23:27:15 +08:00
{
2009-03-31 20:57:34 +08:00
Error ( " Failed to get picture attributes: %s " , strerror ( errno ) ) ;
2009-03-30 23:27:15 +08:00
if ( verbose )
2009-03-31 20:57:34 +08:00
sprintf ( output , " Error, failed to get picture attributes: %s \n " , strerror ( errno ) ) ;
2009-03-30 23:27:15 +08:00
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
if ( verbose )
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " Picture Attributes \n " ) ;
sprintf ( output + strlen ( output ) , " Palette: %d - %s \n " , vid_pic . palette ,
vid_pic . palette = = VIDEO_PALETTE_GREY ? " Linear greyscale " : (
vid_pic . palette = = VIDEO_PALETTE_HI240 ? " High 240 cube (BT848) " : (
vid_pic . palette = = VIDEO_PALETTE_RGB565 ? " 565 16 bit RGB " : (
vid_pic . palette = = VIDEO_PALETTE_RGB24 ? " 24bit RGB " : (
vid_pic . palette = = VIDEO_PALETTE_RGB32 ? " 32bit RGB " : (
vid_pic . palette = = VIDEO_PALETTE_RGB555 ? " 555 15bit RGB " : (
vid_pic . palette = = VIDEO_PALETTE_YUV422 ? " YUV422 capture " : (
vid_pic . palette = = VIDEO_PALETTE_YUYV ? " YUYV " : (
vid_pic . palette = = VIDEO_PALETTE_UYVY ? " UVYV " : (
vid_pic . palette = = VIDEO_PALETTE_YUV420 ? " YUV420 " : (
vid_pic . palette = = VIDEO_PALETTE_YUV411 ? " YUV411 capture " : (
vid_pic . palette = = VIDEO_PALETTE_RAW ? " RAW capture (BT848) " : (
vid_pic . palette = = VIDEO_PALETTE_YUYV ? " YUYV " : (
vid_pic . palette = = VIDEO_PALETTE_YUV422 ? " YUV422 " : (
vid_pic . palette = = VIDEO_PALETTE_YUV422P ? " YUV 4:2:2 Planar " : (
vid_pic . palette = = VIDEO_PALETTE_YUV411P ? " YUV 4:1:1 Planar " : (
vid_pic . palette = = VIDEO_PALETTE_YUV420P ? " YUV 4:2:0 Planar " : (
vid_pic . palette = = VIDEO_PALETTE_YUV410P ? " YUV 4:1:0 Planar " : " Unknown "
) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ;
sprintf ( output + strlen ( output ) , " Colour Depth: %d \n " , vid_pic . depth ) ;
sprintf ( output + strlen ( output ) , " Brightness: %d \n " , vid_pic . brightness ) ;
sprintf ( output + strlen ( output ) , " Hue: %d \n " , vid_pic . hue ) ;
sprintf ( output + strlen ( output ) , " Colour :%d \n " , vid_pic . colour ) ;
sprintf ( output + strlen ( output ) , " Contrast: %d \n " , vid_pic . contrast ) ;
sprintf ( output + strlen ( output ) , " Whiteness: %d \n " , vid_pic . whiteness ) ;
2009-03-30 23:27:15 +08:00
}
else
{
2009-03-31 20:57:34 +08:00
sprintf ( output + strlen ( output ) , " P:%d| " , vid_pic . palette ) ;
sprintf ( output + strlen ( output ) , " D:%d| " , vid_pic . depth ) ;
sprintf ( output + strlen ( output ) , " B:%d| " , vid_pic . brightness ) ;
sprintf ( output + strlen ( output ) , " h:%d| " , vid_pic . hue ) ;
sprintf ( output + strlen ( output ) , " Cl:%d| " , vid_pic . colour ) ;
sprintf ( output + strlen ( output ) , " Cn:%d| " , vid_pic . contrast ) ;
sprintf ( output + strlen ( output ) , " w:%d| " , vid_pic . whiteness ) ;
}
for ( int chan = 0 ; chan < vid_cap . channels ; chan + + )
{
struct video_channel vid_src ;
2011-04-29 22:26:50 +08:00
memset ( & vid_src , 0 , sizeof ( video_channel ) ) ;
2009-03-31 20:57:34 +08:00
vid_src . channel = chan ;
if ( ioctl ( vid_fd , VIDIOCGCHAN , & vid_src ) < 0 )
{
Error ( " Failed to get channel %d attributes: %s " , chan , strerror ( errno ) ) ;
if ( verbose )
sprintf ( output , " Error, failed to get channel %d attributes: %s \n " , chan , strerror ( errno ) ) ;
else
sprintf ( output , " error%d \n " , errno ) ;
return ( false ) ;
}
if ( verbose )
{
sprintf ( output + strlen ( output ) , " Channel %d Attributes \n " , chan ) ;
sprintf ( output + strlen ( output ) , " Name: %s \n " , vid_src . name ) ;
sprintf ( output + strlen ( output ) , " Channel: %d \n " , vid_src . channel ) ;
sprintf ( output + strlen ( output ) , " Flags: %d \n %s%s " , vid_src . flags ,
vid_src . flags & VIDEO_VC_TUNER ? " Channel has a tuner \n " : " " ,
vid_src . flags & VIDEO_VC_AUDIO ? " Channel has audio \n " : " "
) ;
sprintf ( output + strlen ( output ) , " Type: %d - %s \n " , vid_src . type ,
vid_src . type = = VIDEO_TYPE_TV ? " TV " : (
vid_src . type = = VIDEO_TYPE_CAMERA ? " Camera " : " Unknown "
) ) ;
sprintf ( output + strlen ( output ) , " Format: %d - %s \n " , vid_src . norm ,
vid_src . norm = = VIDEO_MODE_PAL ? " PAL " : (
vid_src . norm = = VIDEO_MODE_NTSC ? " NTSC " : (
vid_src . norm = = VIDEO_MODE_SECAM ? " SECAM " : (
vid_src . norm = = VIDEO_MODE_AUTO ? " AUTO " : " Unknown "
) ) ) ) ;
}
else
{
sprintf ( output + strlen ( output ) , " n%d:%s| " , chan , vid_src . name ) ;
sprintf ( output + strlen ( output ) , " C%d:%d| " , chan , vid_src . channel ) ;
sprintf ( output + strlen ( output ) , " Fl%d:%x| " , chan , vid_src . flags ) ;
sprintf ( output + strlen ( output ) , " T%d:%d| " , chan , vid_src . type ) ;
sprintf ( output + strlen ( output ) , " F%d:%d%s| " , chan , vid_src . norm , chan = = ( vid_cap . channels - 1 ) ? " " : " , " ) ;
}
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
if ( ! verbose )
output [ strlen ( output ) - 1 ] = ' \n ' ;
2009-03-30 23:27:15 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-03-31 20:57:34 +08:00
close ( vid_fd ) ;
if ( device )
break ;
2009-03-30 23:27:15 +08:00
}
2009-03-31 20:57:34 +08:00
while ( + + devIndex < 32 ) ;
2003-03-26 19:57:29 +08:00
return ( true ) ;
}
2003-04-13 00:17:17 +08:00
2003-06-25 17:47:09 +08:00
int LocalCamera : : Brightness ( int p_brightness )
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
struct v4l2_control vid_control ;
2003-06-25 17:47:09 +08:00
2008-07-21 23:20:52 +08:00
memset ( & vid_control , 0 , sizeof ( vid_control ) ) ;
vid_control . id = V4L2_CID_BRIGHTNESS ;
if ( vidioctl ( vid_fd , VIDIOC_G_CTRL , & vid_control ) < 0 )
{
if ( errno ! = EINVAL )
Error ( " Unable to query brightness: %s " , strerror ( errno ) )
else
2013-04-30 01:45:27 +08:00
Warning ( " Brightness control is not supported " )
2010-11-03 18:03:58 +08:00
//Info( "Brightness 1 %d", vid_control.value );
2008-07-21 23:20:52 +08:00
}
2009-01-27 19:07:24 +08:00
else if ( p_brightness > = 0 )
2008-07-21 23:20:52 +08:00
{
vid_control . value = p_brightness ;
2010-11-03 18:03:58 +08:00
//Info( "Brightness 2 %d", vid_control.value );
2008-07-21 23:20:52 +08:00
/* The driver may clamp the value or return ERANGE, ignored here */
2009-01-27 19:07:24 +08:00
if ( vidioctl ( vid_fd , VIDIOC_S_CTRL , & vid_control ) )
2008-07-21 23:20:52 +08:00
{
if ( errno ! = ERANGE )
Error ( " Unable to set brightness: %s " , strerror ( errno ) )
else
Warning ( " Given brightness value (%d) may be out-of-range " , p_brightness )
}
2010-11-03 18:03:58 +08:00
//Info( "Brightness 3 %d", vid_control.value );
2008-07-21 23:20:52 +08:00
}
return ( vid_control . value ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
struct video_picture vid_pic ;
2011-04-29 22:26:50 +08:00
memset ( & vid_pic , 0 , sizeof ( video_picture ) ) ;
2008-07-21 23:20:52 +08:00
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
{
Error ( " Failed to get picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
if ( p_brightness > = 0 )
{
vid_pic . brightness = p_brightness ;
if ( ioctl ( vid_fd , VIDIOCSPICT , & vid_pic ) < 0 )
{
Error ( " Failed to set picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
}
return ( vid_pic . brightness ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
return ( - 1 ) ;
2003-06-25 17:47:09 +08:00
}
int LocalCamera : : Hue ( int p_hue )
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
struct v4l2_control vid_control ;
2003-06-25 17:47:09 +08:00
2008-07-21 23:20:52 +08:00
memset ( & vid_control , 0 , sizeof ( vid_control ) ) ;
vid_control . id = V4L2_CID_HUE ;
if ( vidioctl ( vid_fd , VIDIOC_G_CTRL , & vid_control ) < 0 )
{
if ( errno ! = EINVAL )
Error ( " Unable to query hue: %s " , strerror ( errno ) )
else
2013-04-30 01:45:27 +08:00
Warning ( " Hue control is not supported " )
2008-07-21 23:20:52 +08:00
}
2009-01-27 19:07:24 +08:00
else if ( p_hue > = 0 )
2008-07-21 23:20:52 +08:00
{
vid_control . value = p_hue ;
/* The driver may clamp the value or return ERANGE, ignored here */
if ( vidioctl ( vid_fd , VIDIOC_S_CTRL , & vid_control ) < 0 )
{
if ( errno ! = ERANGE )
Error ( " Unable to set hue: %s " , strerror ( errno ) )
else
Warning ( " Given hue value (%d) may be out-of-range " , p_hue )
}
}
return ( vid_control . value ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
struct video_picture vid_pic ;
2011-04-29 22:26:50 +08:00
memset ( & vid_pic , 0 , sizeof ( video_picture ) ) ;
2008-07-21 23:20:52 +08:00
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
{
Error ( " Failed to get picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
if ( p_hue > = 0 )
{
vid_pic . hue = p_hue ;
if ( ioctl ( vid_fd , VIDIOCSPICT , & vid_pic ) < 0 )
{
Error ( " Failed to set picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
}
return ( vid_pic . hue ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
return ( - 1 ) ;
2003-06-25 17:47:09 +08:00
}
int LocalCamera : : Colour ( int p_colour )
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
struct v4l2_control vid_control ;
2003-06-25 17:47:09 +08:00
2008-07-21 23:20:52 +08:00
memset ( & vid_control , 0 , sizeof ( vid_control ) ) ;
vid_control . id = V4L2_CID_SATURATION ;
if ( vidioctl ( vid_fd , VIDIOC_G_CTRL , & vid_control ) < 0 )
{
if ( errno ! = EINVAL )
Error ( " Unable to query saturation: %s " , strerror ( errno ) )
else
2013-04-30 01:45:27 +08:00
Warning ( " Saturation control is not supported " )
2008-07-21 23:20:52 +08:00
}
2009-01-27 19:07:24 +08:00
else if ( p_colour > = 0 )
2008-07-21 23:20:52 +08:00
{
vid_control . value = p_colour ;
/* The driver may clamp the value or return ERANGE, ignored here */
if ( vidioctl ( vid_fd , VIDIOC_S_CTRL , & vid_control ) < 0 )
{
if ( errno ! = ERANGE )
Error ( " Unable to set saturation: %s " , strerror ( errno ) )
else
Warning ( " Given saturation value (%d) may be out-of-range " , p_colour )
}
}
return ( vid_control . value ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
struct video_picture vid_pic ;
2011-04-29 22:26:50 +08:00
memset ( & vid_pic , 0 , sizeof ( video_picture ) ) ;
2008-07-21 23:20:52 +08:00
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
{
Error ( " Failed to get picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
if ( p_colour > = 0 )
{
vid_pic . colour = p_colour ;
if ( ioctl ( vid_fd , VIDIOCSPICT , & vid_pic ) < 0 )
{
Error ( " Failed to set picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
}
return ( vid_pic . colour ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
return ( - 1 ) ;
2003-06-25 17:47:09 +08:00
}
int LocalCamera : : Contrast ( int p_contrast )
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
struct v4l2_control vid_control ;
2003-06-25 17:47:09 +08:00
2008-07-21 23:20:52 +08:00
memset ( & vid_control , 0 , sizeof ( vid_control ) ) ;
vid_control . id = V4L2_CID_CONTRAST ;
if ( vidioctl ( vid_fd , VIDIOC_G_CTRL , & vid_control ) < 0 )
{
if ( errno ! = EINVAL )
Error ( " Unable to query contrast: %s " , strerror ( errno ) )
else
2013-04-30 01:45:27 +08:00
Warning ( " Contrast control is not supported " )
2008-07-21 23:20:52 +08:00
}
2009-01-27 19:07:24 +08:00
else if ( p_contrast > = 0 )
2008-07-21 23:20:52 +08:00
{
vid_control . value = p_contrast ;
/* The driver may clamp the value or return ERANGE, ignored here */
2009-01-27 19:07:24 +08:00
if ( vidioctl ( vid_fd , VIDIOC_S_CTRL , & vid_control ) )
2008-07-21 23:20:52 +08:00
{
if ( errno ! = ERANGE )
Error ( " Unable to set contrast: %s " , strerror ( errno ) )
else
Warning ( " Given contrast value (%d) may be out-of-range " , p_contrast )
}
}
return ( vid_control . value ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
struct video_picture vid_pic ;
2011-04-29 22:26:50 +08:00
memset ( & vid_pic , 0 , sizeof ( video_picture ) ) ;
2008-07-21 23:20:52 +08:00
if ( ioctl ( vid_fd , VIDIOCGPICT , & vid_pic ) < 0 )
{
Error ( " Failed to get picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
if ( p_contrast > = 0 )
{
vid_pic . contrast = p_contrast ;
if ( ioctl ( vid_fd , VIDIOCSPICT , & vid_pic ) < 0 )
{
Error ( " Failed to set picture attributes: %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
}
}
return ( vid_pic . contrast ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
return ( - 1 ) ;
2003-06-25 17:47:09 +08:00
}
2006-10-24 22:37:34 +08:00
int LocalCamera : : PrimeCapture ( )
{
2009-02-13 05:33:05 +08:00
Initialise ( ) ;
2008-07-21 23:20:52 +08:00
Debug ( 2 , " Priming capture " ) ;
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2008-07-21 23:20:52 +08:00
{
2009-02-13 06:26:28 +08:00
Debug ( 3 , " Queueing buffers " ) ;
2013-03-17 07:45:21 +08:00
for ( unsigned int frame = 0 ; frame < v4l2_data . reqbufs . count ; frame + + )
2008-07-21 23:20:52 +08:00
{
2009-02-13 06:26:28 +08:00
struct v4l2_buffer vid_buf ;
2008-07-21 23:20:52 +08:00
2009-02-13 06:26:28 +08:00
memset ( & vid_buf , 0 , sizeof ( vid_buf ) ) ;
2008-07-21 23:20:52 +08:00
2009-02-13 06:26:28 +08:00
vid_buf . type = v4l2_data . fmt . type ;
vid_buf . memory = v4l2_data . reqbufs . memory ;
vid_buf . index = frame ;
2008-07-21 23:20:52 +08:00
2009-02-13 06:26:28 +08:00
if ( vidioctl ( vid_fd , VIDIOC_QBUF , & vid_buf ) < 0 )
Fatal ( " Failed to queue buffer %d: %s " , frame , strerror ( errno ) ) ;
2008-07-21 23:20:52 +08:00
}
2009-02-13 05:33:05 +08:00
v4l2_data . bufptr = NULL ;
2008-07-21 23:20:52 +08:00
Debug ( 3 , " Starting video stream " ) ;
//enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2013-03-17 07:45:21 +08:00
//enum v4l2_buf_type type = v4l2_data.fmt.type;
2013-04-30 01:29:51 +08:00
enum v4l2_buf_type type = ( v4l2_buf_type ) v4l2_data . fmt . type ;
2008-07-21 23:20:52 +08:00
if ( vidioctl ( vid_fd , VIDIOC_STREAMON , & type ) < 0 )
Fatal ( " Failed to start capture stream: %s " , strerror ( errno ) ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2006-10-24 22:37:34 +08:00
{
2009-02-18 05:23:27 +08:00
for ( int frame = 0 ; frame < v4l1_data . frames . frames ; frame + + )
2009-01-28 17:48:06 +08:00
{
2009-02-18 05:23:27 +08:00
Debug ( 3 , " Queueing frame %d " , frame ) ;
if ( ioctl ( vid_fd , VIDIOCMCAPTURE , & v4l1_data . buffers [ frame ] ) < 0 )
2009-01-28 17:48:06 +08:00
{
2009-02-18 05:23:27 +08:00
Error ( " Capture failure for frame %d: %s " , frame , strerror ( errno ) ) ;
return ( - 1 ) ;
2009-01-28 17:48:06 +08:00
}
}
2006-10-24 22:37:34 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-01-28 17:48:06 +08:00
2006-10-24 22:37:34 +08:00
return ( 0 ) ;
}
2003-04-13 00:17:17 +08:00
int LocalCamera : : PreCapture ( )
{
2008-07-21 23:20:52 +08:00
Debug ( 2 , " Pre-capturing " ) ;
2003-04-13 00:17:17 +08:00
return ( 0 ) ;
}
2009-01-28 17:48:06 +08:00
int LocalCamera : : Capture ( Image & image )
2003-04-13 00:17:17 +08:00
{
2011-05-05 17:52:00 +08:00
Debug ( 3 , " Capturing " ) ;
2011-05-08 21:32:42 +08:00
static uint8_t * buffer = NULL ;
static uint8_t * directbuffer = NULL ;
static int capture_frame = - 1 ;
2011-07-01 23:01:24 +08:00
int buffer_bytesused = 0 ;
2011-05-05 17:52:00 +08:00
2005-06-13 18:21:54 +08:00
int captures_per_frame = 1 ;
2006-10-24 22:37:34 +08:00
if ( channel_count > 1 )
2014-07-14 04:39:27 +08:00
captures_per_frame = v4l_captures_per_frame ;
2014-07-15 02:07:28 +08:00
if ( captures_per_frame < = 0 ) {
captures_per_frame = 1 ;
Warning ( " Invalid Captures Per Frame setting: %d " , captures_per_frame ) ;
}
2011-05-05 17:52:00 +08:00
2009-01-28 20:50:37 +08:00
// Do the capture, unless we are the second or subsequent camera on a channel, in which case just reuse the buffer
if ( channel_prime )
2006-10-24 22:37:34 +08:00
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2006-10-24 22:37:34 +08:00
{
2008-07-21 23:20:52 +08:00
static struct v4l2_buffer vid_buf ;
memset ( & vid_buf , 0 , sizeof ( vid_buf ) ) ;
vid_buf . type = v4l2_data . fmt . type ;
//vid_buf.memory = V4L2_MEMORY_MMAP;
vid_buf . memory = v4l2_data . reqbufs . memory ;
Debug ( 3 , " Capturing %d frames " , captures_per_frame ) ;
while ( captures_per_frame )
2006-10-24 22:37:34 +08:00
{
2008-07-21 23:20:52 +08:00
if ( vidioctl ( vid_fd , VIDIOC_DQBUF , & vid_buf ) < 0 )
{
if ( errno = = EIO )
Warning ( " Capture failure, possible signal loss?: %s " , strerror ( errno ) )
else
Error ( " Unable to capture frame %d: %s " , vid_buf . index , strerror ( errno ) )
return ( - 1 ) ;
}
2009-02-13 05:33:05 +08:00
v4l2_data . bufptr = & vid_buf ;
capture_frame = v4l2_data . bufptr - > index ;
2009-02-13 06:26:28 +08:00
if ( - - captures_per_frame )
2008-07-21 23:20:52 +08:00
{
if ( vidioctl ( vid_fd , VIDIOC_QBUF , & vid_buf ) < 0 )
{
Error ( " Unable to requeue buffer %d: %s " , vid_buf . index , strerror ( errno ) ) ;
return ( - 1 ) ;
}
}
2006-10-24 22:37:34 +08:00
}
2009-01-28 17:48:06 +08:00
2009-02-13 05:33:05 +08:00
Debug ( 3 , " Captured frame %d/%d from channel %d " , capture_frame , v4l2_data . bufptr - > sequence , channel ) ;
2008-07-21 23:20:52 +08:00
2009-02-13 05:33:05 +08:00
buffer = ( unsigned char * ) v4l2_data . buffers [ v4l2_data . bufptr - > index ] . start ;
2011-07-01 23:01:24 +08:00
buffer_bytesused = v4l2_data . bufptr - > bytesused ;
2011-01-21 02:49:42 +08:00
2012-03-07 20:33:09 +08:00
if ( ( v4l2_data . fmt . fmt . pix . width * v4l2_data . fmt . fmt . pix . height ) ! = ( width * height ) ) {
2011-05-05 17:52:00 +08:00
Fatal ( " Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d " , v4l2_data . fmt . fmt . pix . width , v4l2_data . fmt . fmt . pix . height , width , height ) ;
}
2008-07-21 23:20:52 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2008-07-21 23:20:52 +08:00
{
Debug ( 3 , " Capturing %d frames " , captures_per_frame ) ;
while ( captures_per_frame )
2006-10-24 22:37:34 +08:00
{
2009-02-18 05:23:27 +08:00
Debug ( 3 , " Syncing frame %d " , v4l1_data . active_frame ) ;
if ( ioctl ( vid_fd , VIDIOCSYNC , & v4l1_data . active_frame ) < 0 )
2006-10-24 22:37:34 +08:00
{
2009-02-18 05:23:27 +08:00
Error ( " Sync failure for frame %d buffer %d: %s " , v4l1_data . active_frame , captures_per_frame , strerror ( errno ) ) ;
2006-10-24 22:37:34 +08:00
return ( - 1 ) ;
}
2008-07-21 23:20:52 +08:00
captures_per_frame - - ;
if ( captures_per_frame )
{
2009-02-18 05:23:27 +08:00
Debug ( 3 , " Capturing frame %d " , v4l1_data . active_frame ) ;
if ( ioctl ( vid_fd , VIDIOCMCAPTURE , & v4l1_data . buffers [ v4l1_data . active_frame ] ) < 0 )
2008-07-21 23:20:52 +08:00
{
2009-02-18 05:23:27 +08:00
Error ( " Capture failure for buffer %d (%d): %s " , v4l1_data . active_frame , captures_per_frame , strerror ( errno ) ) ;
2008-07-21 23:20:52 +08:00
return ( - 1 ) ;
}
}
2006-10-24 22:37:34 +08:00
}
2009-02-18 05:23:27 +08:00
capture_frame = v4l1_data . active_frame ;
2009-01-28 17:48:06 +08:00
Debug ( 3 , " Captured %d for channel %d " , capture_frame , channel ) ;
2008-07-21 23:20:52 +08:00
2009-02-18 05:23:27 +08:00
buffer = v4l1_data . bufptr + v4l1_data . frames . offsets [ capture_frame ] ;
2006-10-24 22:37:34 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2011-05-08 21:32:42 +08:00
} /* prime capture */
2011-05-05 17:52:00 +08:00
if ( conversion_type ! = 0 ) {
Debug ( 3 , " Performing format conversion " ) ;
/* Request a writeable buffer of the target image */
directbuffer = image . WriteBuffer ( width , height , colours , subpixelorder ) ;
if ( directbuffer = = NULL ) {
Error ( " Failed requesting writeable buffer for the captured image. " ) ;
return ( - 1 ) ;
}
2011-01-21 02:49:42 +08:00
# if HAVE_LIBSWSCALE
2011-05-05 17:52:00 +08:00
if ( conversion_type = = 1 ) {
2011-07-05 23:23:02 +08:00
Debug ( 9 , " Calling sws_scale to perform the conversion " ) ;
/* Use swscale to convert the image directly into the shared memory */
2011-05-07 04:07:40 +08:00
avpicture_fill ( ( AVPicture * ) tmpPicture , directbuffer , imagePixFormat , width , height ) ;
2011-05-05 17:52:00 +08:00
sws_scale ( imgConversionContext , capturePictures [ capture_frame ] - > data , capturePictures [ capture_frame ] - > linesize , 0 , height , tmpPicture - > data , tmpPicture - > linesize ) ;
2011-05-07 23:39:16 +08:00
}
# endif
if ( conversion_type = = 2 ) {
2011-05-05 17:52:00 +08:00
2011-07-05 23:23:02 +08:00
Debug ( 9 , " Calling the conversion function " ) ;
2011-05-05 17:52:00 +08:00
/* Call the image conversion function and convert directly into the shared memory */
( * conversion_fptr ) ( buffer , directbuffer , pixels ) ;
}
2011-07-01 23:01:24 +08:00
else if ( conversion_type = = 3 ) {
2011-07-05 23:23:02 +08:00
Debug ( 9 , " Decoding the JPEG image " ) ;
2011-07-01 23:01:24 +08:00
/* JPEG decoding */
image . DecodeJpeg ( buffer , buffer_bytesused , colours , subpixelorder ) ;
}
2011-05-05 17:52:00 +08:00
} else {
Debug ( 3 , " No format conversion performed. Assigning the image " ) ;
2011-04-29 22:26:50 +08:00
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
image . Assign ( width , height , colours , subpixelorder , buffer , imagesize ) ;
2011-05-05 17:52:00 +08:00
}
2003-04-13 00:17:17 +08:00
return ( 0 ) ;
}
2009-01-28 17:48:06 +08:00
int LocalCamera : : PostCapture ( )
{
Debug ( 2 , " Post-capturing " ) ;
2009-02-17 02:18:03 +08:00
// Requeue the buffer unless we need to switch or are a duplicate camera on a channel
2011-05-08 21:32:42 +08:00
if ( channel_count > 1 | | channel_prime )
2009-01-28 17:48:06 +08:00
{
2011-02-16 05:59:06 +08:00
# if ZM_HAS_V4L2
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 2 )
2009-01-28 17:48:06 +08:00
{
2009-02-13 06:26:28 +08:00
if ( channel_count > 1 )
{
int next_channel = ( channel_index + 1 ) % channel_count ;
Debug ( 3 , " Switching video source to %d " , channels [ next_channel ] ) ;
if ( vidioctl ( vid_fd , VIDIOC_S_INPUT , & channels [ next_channel ] ) < 0 )
{
2009-03-30 23:27:15 +08:00
Error ( " Failed to set camera source %d: %s " , channels [ next_channel ] , strerror ( errno ) ) ;
2009-02-13 06:26:28 +08:00
return ( - 1 ) ;
}
2009-02-18 05:23:27 +08:00
v4l2_std_id stdId = standards [ next_channel ] ;
2009-02-13 06:26:28 +08:00
if ( vidioctl ( vid_fd , VIDIOC_S_STD , & stdId ) < 0 )
{
2009-02-18 05:23:27 +08:00
Error ( " Failed to set video format %d: %s " , standards [ next_channel ] , strerror ( errno ) ) ;
2009-02-13 06:26:28 +08:00
return ( - 1 ) ;
}
}
2014-09-09 04:56:40 +08:00
if ( v4l2_data . bufptr ) {
Debug ( 3 , " Requeueing buffer %d " , v4l2_data . bufptr - > index ) ;
if ( vidioctl ( vid_fd , VIDIOC_QBUF , v4l2_data . bufptr ) < 0 )
{
Error ( " Unable to requeue buffer %d: %s " , v4l2_data . bufptr - > index , strerror ( errno ) )
return ( - 1 ) ;
}
2014-09-09 04:46:41 +08:00
} else {
Error ( " Unable to requeue buffer due to not v4l2_data " )
}
2009-01-28 17:48:06 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L2
# if ZM_HAS_V4L1
2009-02-13 05:33:05 +08:00
if ( v4l_version = = 1 )
2009-01-28 17:48:06 +08:00
{
2009-02-18 05:23:27 +08:00
if ( channel_count > 1 )
{
Debug ( 3 , " Switching video source " ) ;
int next_channel = ( channel_index + 1 ) % channel_count ;
struct video_channel vid_src ;
memset ( & vid_src , 0 , sizeof ( vid_src ) ) ;
vid_src . channel = channel ;
if ( ioctl ( vid_fd , VIDIOCGCHAN , & vid_src ) < 0 )
{
Error ( " Failed to get camera source %d: %s " , channel , strerror ( errno ) ) ;
return ( - 1 ) ;
}
vid_src . channel = channels [ next_channel ] ;
vid_src . norm = standards [ next_channel ] ;
vid_src . flags = 0 ;
vid_src . type = VIDEO_TYPE_CAMERA ;
if ( ioctl ( vid_fd , VIDIOCSCHAN , & vid_src ) < 0 )
{
Error ( " Failed to set camera source %d: %s " , channel , strerror ( errno ) ) ;
return ( - 1 ) ;
}
}
Debug ( 3 , " Requeueing frame %d " , v4l1_data . active_frame ) ;
if ( ioctl ( vid_fd , VIDIOCMCAPTURE , & v4l1_data . buffers [ v4l1_data . active_frame ] ) < 0 )
2009-01-28 17:48:06 +08:00
{
2009-02-18 05:23:27 +08:00
Error ( " Capture failure for frame %d: %s " , v4l1_data . active_frame , strerror ( errno ) ) ;
2009-01-28 17:48:06 +08:00
return ( - 1 ) ;
}
2009-02-18 05:23:27 +08:00
v4l1_data . active_frame = ( v4l1_data . active_frame + 1 ) % v4l1_data . frames . frames ;
2009-01-28 17:48:06 +08:00
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L1
2009-01-28 17:48:06 +08:00
}
return ( 0 ) ;
}
2011-02-16 05:59:06 +08:00
# endif // ZM_HAS_V4L