2010-05-12 01:44:00 +08:00
/* This is the contributed code:
File : cvcap_v4l . cpp
2014-07-10 22:27:32 +08:00
Current Location : . . / opencv - 0.9 .6 / otherlibs / videoio
2010-05-12 01:44:00 +08:00
Original Version : 2003 - 03 - 12 Magnus Lundin lundin @ mlu . mine . nu
Original Comments :
ML : This set of files adds support for firevre and usb cameras .
First it tries to install a firewire camera ,
if that fails it tries a v4l / USB camera
It has been tested with the motempl sample program
First Patch : August 24 , 2004 Travis Wood TravisOCV @ tkwood . com
For Release : OpenCV - Linux Beta4 opencv - 0.9 .6
Tested On : LMLBT44 with 8 video inputs
2013-08-21 20:44:09 +08:00
Problems ? Post your questions at answers . opencv . org ,
2013-06-28 16:21:52 +08:00
Report bugs at code . opencv . org ,
2016-06-14 21:01:36 +08:00
Submit your fixes at https : //github.com/opencv/opencv/
2010-05-12 01:44:00 +08:00
Patched Comments :
TW : The cv cam utils that came with the initial release of OpenCV for LINUX Beta4
were not working . I have rewritten them so they work for me . At the same time , trying
to keep the original code as ML wrote it as unchanged as possible . No one likes to debug
someone elses code , so I resisted changes as much as possible . I have tried to keep the
same " ideas " where applicable , that is , where I could figure out what the previous author
intended . Some areas I just could not help myself and had to " spiffy-it-up " my way .
These drivers should work with other V4L frame capture cards other then my bttv
driven frame capture card .
Re Written driver for standard V4L mode . Tested using LMLBT44 video capture card .
Standard bttv drivers are on the LMLBT44 with up to 8 Inputs .
This utility was written with the help of the document :
http : //pages.cpsc.ucalgary.ca/~sayles/VFL_HowTo
as a general guide for interfacing into the V4l standard .
Made the index value passed for icvOpenCAM_V4L ( index ) be the number of the
video device source in the / dev tree . The - 1 uses original / dev / video .
Index Device
0 / dev / video0
1 / dev / video1
2 / dev / video2
3 / dev / video3
. . .
7 / dev / video7
with
- 1 / dev / video
TW : You can select any video source , but this package was limited from the start to only
ONE camera opened at any ONE time .
This is an original program limitation .
If you are interested , I will make my version available to other OpenCV users . The big
difference in mine is you may pass the camera number as part of the cv argument , but this
convention is non standard for current OpenCV calls and the camera number is not currently
passed into the called routine .
Second Patch : August 28 , 2004 Sfuncia Fabio fiblan @ yahoo . it
For Release : OpenCV - Linux Beta4 Opencv - 0.9 .6
FS : this patch fix not sequential index of device ( unplugged device ) , and real numCameras .
2018-02-14 00:28:11 +08:00
for - 1 index ( icvOpenCAM_V4L ) I don ' t use / dev / video but real device available , because
2010-05-12 01:44:00 +08:00
if / dev / video is a link to / dev / video0 and i unplugged device on / dev / video0 , / dev / video
is a bad link . I search the first available device with indexList .
Third Patch : December 9 , 2004 Frederic Devernay Frederic . Devernay @ inria . fr
For Release : OpenCV - Linux Beta4 Opencv - 0.9 .6
[ FD ] I modified the following :
- handle YUV420P , YUV420 , and YUV411P palettes ( for many webcams ) without using floating - point
- cvGrabFrame should not wait for the end of the first frame , and should return quickly
2014-07-10 22:27:32 +08:00
( see videoio doc )
2010-05-12 01:44:00 +08:00
- cvRetrieveFrame should in turn wait for the end of frame capture , and should not
trigger the capture of the next frame ( the user choses when to do it using GrabFrame )
To get the old behavior , re - call cvRetrieveFrame just after cvGrabFrame .
- having global bufferIndex and FirstCapture variables makes the code non - reentrant
( e . g . when using several cameras ) , put these in the CvCapture struct .
- according to V4L HowTo , incrementing the buffer index must be done before VIDIOCMCAPTURE .
- the VID_TYPE_SCALES stuff from V4L HowTo is wrong : image size can be changed
even if the hardware does not support scaling ( e . g . webcams can have several
resolutions available ) . Just don ' t try to set the size at 640 x480 if the hardware supports
scaling : open with the default ( probably best ) image size , and let the user scale it
using SetProperty .
- image size can be changed by two subsequent calls to SetProperty ( for width and height )
- bug fix : if the image size changes , realloc the new image only when it is grabbed
- issue errors only when necessary , fix error message formatting .
Fourth Patch : Sept 7 , 2005 Csaba Kertesz sign @ freemail . hu
For Release : OpenCV - Linux Beta5 OpenCV - 0.9 .7
I modified the following :
- Additional Video4Linux2 support : )
- Use mmap functions ( v4l2 )
- New methods are internal :
try_palette_v4l2 - > rewrite try_palette for v4l2
mainloop_v4l2 , read_image_v4l2 - > this methods are moved from official v4l2 capture . c example
try_init_v4l - > device v4l initialisation
try_init_v4l2 - > device v4l2 initialisation
autosetup_capture_mode_v4l - > autodetect capture modes for v4l
autosetup_capture_mode_v4l2 - > autodetect capture modes for v4l2
- Modifications are according with Video4Linux old codes
- Video4Linux handling is automatically if it does not recognize a Video4Linux2 device
2015-05-23 21:26:18 +08:00
- Tested successfully with Logitech Quickcam Express ( V4L ) , Creative Vista ( V4L ) and Genius VideoCam Notebook ( V4L2 )
2010-05-12 01:44:00 +08:00
- Correct source lines with compiler warning messages
- Information message from v4l / v4l2 detection
Fifth Patch : Sept 7 , 2005 Csaba Kertesz sign @ freemail . hu
For Release : OpenCV - Linux Beta5 OpenCV - 0.9 .7
I modified the following :
- SN9C10x chip based webcams support
- New methods are internal :
bayer2rgb24 , sonix_decompress - > decoder routines for SN9C10x decoding from Takafumi Mizuno < taka - qce @ ls - a . jp > with his pleasure : )
2015-05-23 21:26:18 +08:00
- Tested successfully with Genius VideoCam Notebook ( V4L2 )
2010-05-12 01:44:00 +08:00
Sixth Patch : Sept 10 , 2005 Csaba Kertesz sign @ freemail . hu
For Release : OpenCV - Linux Beta5 OpenCV - 0.9 .7
I added the following :
- Add capture control support ( hue , saturation , brightness , contrast , gain )
- Get and change V4L capture controls ( hue , saturation , brightness , contrast )
- New method is internal :
icvSetControl - > set capture controls
2015-05-23 21:26:18 +08:00
- Tested successfully with Creative Vista ( V4L )
2010-05-12 01:44:00 +08:00
Seventh Patch : Sept 10 , 2005 Csaba Kertesz sign @ freemail . hu
For Release : OpenCV - Linux Beta5 OpenCV - 0.9 .7
I added the following :
- Detect , get and change V4L2 capture controls ( hue , saturation , brightness , contrast , gain )
- New methods are internal :
v4l2_scan_controls_enumerate_menu , v4l2_scan_controls - > detect capture control intervals
2015-05-23 21:26:18 +08:00
- Tested successfully with Genius VideoCam Notebook ( V4L2 )
2010-05-12 01:44:00 +08:00
8 th patch : Jan 5 , 2006 , Olivier . Bornet @ idiap . ch
Add support of V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG .
With this patch , new webcams of Logitech , like QuickCam Fusion works .
Note : For use these webcams , look at the UVC driver at
http : //linux-uvc.berlios.de/
9 th patch : Mar 4 , 2006 , Olivier . Bornet @ idiap . ch
- try V4L2 before V4L , because some devices are V4L2 by default ,
but they try to implement the V4L compatibility layer .
So , I think this is better to support V4L2 before V4L .
- better separation between V4L2 and V4L initialization . ( this was needed to support
some drivers working , but not fully with V4L2 . ( so , we do not know when we
need to switch from V4L2 to V4L .
10 th patch : July 02 , 2008 , Mikhail Afanasyev fopencv @ theamk . com
Fix reliability problems with high - resolution UVC cameras on linux
the symptoms were damaged image and ' Corrupt JPEG data : premature end of data segment ' on stderr
- V4L_ABORT_BADJPEG detects JPEG warnings and turns them into errors , so bad images
could be filtered out
- USE_TEMP_BUFFER fixes the main problem ( improper buffer management ) and
prevents bad images in the first place
2013-04-03 01:31:02 +08:00
11 th patch : April 2 , 2013 , Forrest Reiling forrest . reiling @ gmail . com
2013-08-21 20:44:09 +08:00
Added v4l2 support for getting capture property CV_CAP_PROP_POS_MSEC .
2013-04-03 01:31:02 +08:00
Returns the millisecond timestamp of the last frame grabbed or 0 if no frames have been grabbed
2018-02-14 00:28:11 +08:00
Used to successfully synchronize 2 Logitech C310 USB webcams to within 16 ms of one another
2013-04-03 01:31:02 +08:00
2018-04-09 22:34:00 +08:00
12 th patch : March 9 , 2018 , Taylor Lanclos < tlanclos @ live . com >
added support for CV_CAP_PROP_BUFFERSIZE
2010-05-12 01:44:00 +08:00
make & enjoy !
*/
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
# include "precomp.hpp"
2017-07-25 18:23:44 +08:00
# if !defined _WIN32 && (defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO)
2010-05-12 01:44:00 +08:00
# include <stdio.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
# include <sys/ioctl.h>
# include <sys/types.h>
# include <sys/mman.h>
# include <string.h>
# include <stdlib.h>
# include <assert.h>
# include <sys/stat.h>
# include <sys/ioctl.h>
2019-02-26 18:15:59 +08:00
# include <limits>
2010-05-12 01:44:00 +08:00
# ifdef HAVE_CAMV4L2
2012-09-17 18:03:35 +08:00
# include <asm/types.h> /* for videodev2.h */
2010-05-12 01:44:00 +08:00
# include <linux/videodev2.h>
# endif
2012-09-17 17:08:37 +08:00
# ifdef HAVE_VIDEOIO
2018-02-14 00:28:11 +08:00
// NetBSD compatibility layer with V4L2
2012-09-17 17:08:37 +08:00
# include <sys/videoio.h>
# endif
2018-12-20 21:28:12 +08:00
// https://github.com/opencv/opencv/issues/13335
# ifndef V4L2_CID_ISO_SENSITIVITY
# define V4L2_CID_ISO_SENSITIVITY (V4L2_CID_CAMERA_CLASS_BASE+23)
# endif
2019-03-04 23:45:01 +08:00
// https://github.com/opencv/opencv/issues/13929
# ifndef V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT
# define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_MPEG_BASE+364)
# endif
# ifndef V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH
# define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_MPEG_BASE+365)
# endif
2019-04-29 23:14:58 +08:00
# ifndef V4L2_CID_ROTATE
# define V4L2_CID_ROTATE (V4L2_CID_BASE+34)
# endif
# ifndef V4L2_CID_IRIS_ABSOLUTE
# define V4L2_CID_IRIS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+17)
# endif
2019-07-26 20:37:28 +08:00
# ifndef V4L2_PIX_FMT_Y10
# define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ')
# endif
2010-05-12 01:44:00 +08:00
/* Defaults - If your board can do better, set it here. Set for the most common type inputs. */
# define DEFAULT_V4L_WIDTH 640
# define DEFAULT_V4L_HEIGHT 480
2015-10-09 22:01:14 +08:00
# define DEFAULT_V4L_FPS 30
2010-05-12 01:44:00 +08:00
# define MAX_CAMERAS 8
// default and maximum number of V4L buffers, not including last, 'special' buffer
# define MAX_V4L_BUFFERS 10
# define DEFAULT_V4L_BUFFERS 4
// if enabled, then bad JPEG warnings become errors and cause NULL returned instead of image
# define V4L_ABORT_BADJPEG
2015-10-24 08:07:26 +08:00
namespace cv {
2019-11-23 05:03:52 +08:00
static const char * decode_ioctl_code ( unsigned long ioctlCode )
{
switch ( ioctlCode )
{
# define CV_ADD_IOCTL_CODE(id) case id: return #id
CV_ADD_IOCTL_CODE ( VIDIOC_G_FMT ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_S_FMT ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_REQBUFS ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_DQBUF ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_QUERYCAP ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_S_PARM ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_G_PARM ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_QUERYBUF ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_QBUF ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_STREAMON ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_STREAMOFF ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_ENUMINPUT ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_G_INPUT ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_S_INPUT ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_G_CTRL ) ;
CV_ADD_IOCTL_CODE ( VIDIOC_S_CTRL ) ;
# undef CV_ADD_IOCTL_CODE
}
return " unknown " ;
}
2010-05-12 01:44:00 +08:00
/* Device Capture Objects */
/* V4L2 structure */
2018-11-09 02:27:45 +08:00
struct Buffer
2010-05-12 01:44:00 +08:00
{
2018-05-31 18:37:13 +08:00
void * start ;
size_t length ;
2018-11-09 02:27:45 +08:00
// This is dequeued buffer. It used for to put it back in the queue.
// The buffer is valid only if capture->bufferIndex >= 0
v4l2_buffer buffer ;
Buffer ( ) : start ( NULL ) , length ( 0 )
{
buffer = v4l2_buffer ( ) ;
}
2010-05-12 01:44:00 +08:00
} ;
2018-03-15 21:16:53 +08:00
struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
2010-05-12 01:44:00 +08:00
{
2018-09-16 04:54:03 +08:00
int getCaptureDomain ( ) /*const*/ CV_OVERRIDE { return cv : : CAP_V4L ; }
2010-05-12 01:44:00 +08:00
int deviceHandle ;
2019-11-23 05:03:52 +08:00
bool v4l_buffersRequested ;
bool v4l_streamStarted ;
2010-05-12 01:44:00 +08:00
int bufferIndex ;
2018-11-09 02:27:45 +08:00
bool FirstCapture ;
2016-04-12 13:00:37 +08:00
String deviceName ;
2015-10-24 07:45:44 +08:00
2010-05-12 01:44:00 +08:00
IplImage frame ;
2018-05-31 18:37:13 +08:00
__u32 palette ;
int width , height ;
2018-07-19 16:40:27 +08:00
int width_set , height_set ;
2018-05-31 18:37:13 +08:00
int bufferSize ;
__u32 fps ;
bool convert_rgb ;
bool frame_allocated ;
bool returnFrame ;
2018-11-09 02:27:45 +08:00
// To select a video input set cv::CAP_PROP_CHANNEL to channel number.
// If the new channel number is than 0, then a video input will not change
int channelNumber ;
// Normalize properties. If set parameters will be converted to/from [0,1) range.
// Enabled by default (as OpenCV 3.x does).
// Value is initialized from the environment variable `OPENCV_VIDEOIO_V4L_RANGE_NORMALIZED`:
// To select real parameters mode after devise is open set cv::CAP_PROP_MODE to 0
// any other value revert the backward compatibility mode (with normalized properties).
// Range normalization affects the following parameters:
// cv::CAP_PROP_*: BRIGHTNESS,CONTRAST,SATURATION,HUE,GAIN,EXPOSURE,FOCUS,AUTOFOCUS,AUTO_EXPOSURE.
bool normalizePropRange ;
2018-05-31 18:37:13 +08:00
/* V4L2 variables */
2018-11-09 02:27:45 +08:00
Buffer buffers [ MAX_V4L_BUFFERS + 1 ] ;
v4l2_capability capability ;
v4l2_input videoInput ;
2018-05-31 18:37:13 +08:00
v4l2_format form ;
v4l2_requestbuffers req ;
v4l2_buf_type type ;
timeval timestamp ;
bool open ( int _index ) ;
bool open ( const char * deviceName ) ;
2018-11-09 02:27:45 +08:00
bool isOpened ( ) const ;
2018-05-31 18:37:13 +08:00
2019-11-23 05:03:52 +08:00
void closeDevice ( ) ;
2018-05-31 18:37:13 +08:00
virtual double getProperty ( int ) const CV_OVERRIDE ;
virtual bool setProperty ( int , double ) CV_OVERRIDE ;
virtual bool grabFrame ( ) CV_OVERRIDE ;
virtual IplImage * retrieveFrame ( int ) CV_OVERRIDE ;
2018-11-09 02:27:45 +08:00
CvCaptureCAM_V4L ( ) ;
2018-05-31 18:37:13 +08:00
virtual ~ CvCaptureCAM_V4L ( ) ;
2018-11-09 02:27:45 +08:00
bool requestBuffers ( ) ;
bool requestBuffers ( unsigned int buffer_number ) ;
bool createBuffers ( ) ;
void releaseBuffers ( ) ;
bool initCapture ( ) ;
bool streaming ( bool startStream ) ;
bool setFps ( int value ) ;
2019-11-23 06:10:16 +08:00
bool tryIoctl ( unsigned long ioctlCode , void * parameter , bool failIfBusy = true , int attempts = 10 ) const ;
2018-11-09 02:27:45 +08:00
bool controlInfo ( int property_id , __u32 & v4l2id , cv : : Range & range ) const ;
bool icvControl ( __u32 v4l2id , int & value , bool isSet ) const ;
bool icvSetFrameSize ( int _width , int _height ) ;
bool v4l2_reset ( ) ;
bool setVideoInputChannel ( ) ;
bool try_palette_v4l2 ( ) ;
bool try_init_v4l2 ( ) ;
bool autosetup_capture_mode_v4l2 ( ) ;
void v4l2_create_frame ( ) ;
bool read_frame_v4l2 ( ) ;
bool convertableToRgb ( ) const ;
void convertToRgb ( const Buffer & currentBuffer ) ;
void releaseFrame ( ) ;
2015-10-24 08:07:26 +08:00
} ;
2010-05-12 01:44:00 +08:00
/*********************** Implementations ***************************************/
2018-12-03 18:30:41 +08:00
CvCaptureCAM_V4L : : CvCaptureCAM_V4L ( ) :
2019-11-23 05:03:52 +08:00
deviceHandle ( - 1 ) ,
v4l_buffersRequested ( false ) ,
v4l_streamStarted ( false ) ,
bufferIndex ( - 1 ) ,
2018-12-03 18:30:41 +08:00
FirstCapture ( true ) ,
palette ( 0 ) ,
width ( 0 ) , height ( 0 ) , width_set ( 0 ) , height_set ( 0 ) ,
bufferSize ( DEFAULT_V4L_BUFFERS ) ,
fps ( 0 ) , convert_rgb ( 0 ) , frame_allocated ( false ) , returnFrame ( false ) ,
channelNumber ( - 1 ) , normalizePropRange ( false ) ,
type ( V4L2_BUF_TYPE_VIDEO_CAPTURE )
2018-11-11 21:51:47 +08:00
{
2018-12-03 18:30:41 +08:00
frame = cvIplImage ( ) ;
2018-11-11 21:51:47 +08:00
memset ( & timestamp , 0 , sizeof ( timestamp ) ) ;
}
2018-11-09 02:27:45 +08:00
2019-11-23 05:03:52 +08:00
CvCaptureCAM_V4L : : ~ CvCaptureCAM_V4L ( )
{
try
{
closeDevice ( ) ;
}
catch ( . . . )
{
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2): unable properly close device: " < < deviceName ) ;
if ( deviceHandle ! = - 1 )
close ( deviceHandle ) ;
}
}
void CvCaptureCAM_V4L : : closeDevice ( )
{
if ( v4l_streamStarted )
streaming ( false ) ;
if ( v4l_buffersRequested )
releaseBuffers ( ) ;
2018-11-09 02:27:45 +08:00
if ( deviceHandle ! = - 1 )
2019-11-23 05:03:52 +08:00
{
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): close( " < < deviceHandle < < " ) " ) ;
2018-11-09 02:27:45 +08:00
close ( deviceHandle ) ;
2019-11-23 05:03:52 +08:00
}
deviceHandle = - 1 ;
2018-11-09 02:27:45 +08:00
}
bool CvCaptureCAM_V4L : : isOpened ( ) const
{
return deviceHandle ! = - 1 ;
2015-10-24 08:07:26 +08:00
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : try_palette_v4l2 ( )
2010-05-12 01:44:00 +08:00
{
2018-11-09 02:27:45 +08:00
form = v4l2_format ( ) ;
form . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
form . fmt . pix . pixelformat = palette ;
form . fmt . pix . field = V4L2_FIELD_ANY ;
form . fmt . pix . width = width ;
form . fmt . pix . height = height ;
2019-11-23 05:03:52 +08:00
if ( ! tryIoctl ( VIDIOC_S_FMT , & form , true ) )
2019-11-23 06:10:16 +08:00
{
2018-05-31 18:37:13 +08:00
return false ;
2019-11-23 06:10:16 +08:00
}
2018-11-09 02:27:45 +08:00
return palette = = form . fmt . pix . pixelformat ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : setVideoInputChannel ( )
2010-05-12 01:44:00 +08:00
{
2018-11-09 02:27:45 +08:00
if ( channelNumber < 0 )
return true ;
/* Query channels number */
int channel = 0 ;
if ( ! tryIoctl ( VIDIOC_G_INPUT , & channel ) )
return false ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
if ( channel = = channelNumber )
return true ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
/* Query information about new input channel */
videoInput = v4l2_input ( ) ;
videoInput . index = channelNumber ;
if ( ! tryIoctl ( VIDIOC_ENUMINPUT , & videoInput ) )
return false ;
//To select a video input applications store the number of the desired input in an integer
// and call the VIDIOC_S_INPUT ioctl with a pointer to this integer. Side effects are possible.
// For example inputs may support different video standards, so the driver may implicitly
// switch the current standard.
// It is good practice to select an input before querying or negotiating any other parameters.
return tryIoctl ( VIDIOC_S_INPUT , & channelNumber ) ;
}
bool CvCaptureCAM_V4L : : try_init_v4l2 ( )
{
/* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
have sub " Channel Numbers " . For a typical V4L TV capture card , this is usually 1.
I myself am using a simple NTSC video input capture card that uses the value of 1.
If you are not in North America or have a different video standard , you WILL have to change
the following settings and recompile / reinstall . This set of settings is based on
the most commonly encountered input video source types ( like my bttv card ) */
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
// The cv::CAP_PROP_MODE used for set the video input channel number
if ( ! setVideoInputChannel ( ) )
2018-05-31 18:37:13 +08:00
{
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Unable to set Video Input Channel " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
// Test device for V4L2 compatibility
capability = v4l2_capability ( ) ;
if ( ! tryIoctl ( VIDIOC_QUERYCAP , & capability ) )
2018-05-31 18:37:13 +08:00
{
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Unable to query capability " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
if ( ( capability . capabilities & V4L2_CAP_VIDEO_CAPTURE ) = = 0 )
2018-05-31 18:37:13 +08:00
{
2018-11-09 02:27:45 +08:00
/* Nope. */
2019-11-23 05:03:52 +08:00
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): not supported - device is unable to capture video (missing V4L2_CAP_VIDEO_CAPTURE) " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
return true ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : autosetup_capture_mode_v4l2 ( )
{
2016-09-16 04:13:38 +08:00
//in case palette is already set and works, no need to setup.
2019-11-23 05:03:52 +08:00
if ( palette ! = 0 )
{
if ( try_palette_v4l2 ( ) )
{
return true ;
}
else if ( errno = = EBUSY )
{
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): device is busy " ) ;
closeDevice ( ) ;
return false ;
}
2016-09-16 04:13:38 +08:00
}
2015-10-10 18:39:37 +08:00
__u32 try_order [ ] = {
V4L2_PIX_FMT_BGR24 ,
2017-08-27 15:21:10 +08:00
V4L2_PIX_FMT_RGB24 ,
2015-10-10 18:39:37 +08:00
V4L2_PIX_FMT_YVU420 ,
2018-08-02 23:34:11 +08:00
V4L2_PIX_FMT_YUV420 ,
2015-10-10 18:39:37 +08:00
V4L2_PIX_FMT_YUV411P ,
V4L2_PIX_FMT_YUYV ,
V4L2_PIX_FMT_UYVY ,
2018-11-09 02:27:45 +08:00
V4L2_PIX_FMT_NV12 ,
V4L2_PIX_FMT_NV21 ,
2015-10-10 18:39:37 +08:00
V4L2_PIX_FMT_SBGGR8 ,
V4L2_PIX_FMT_SGBRG8 ,
2017-08-27 15:21:10 +08:00
V4L2_PIX_FMT_SN9C10X ,
# ifdef HAVE_JPEG
V4L2_PIX_FMT_MJPEG ,
V4L2_PIX_FMT_JPEG ,
# endif
2018-11-09 02:27:45 +08:00
V4L2_PIX_FMT_Y16 ,
2019-07-09 20:00:17 +08:00
V4L2_PIX_FMT_Y10 ,
V4L2_PIX_FMT_GREY ,
2015-10-10 18:39:37 +08:00
} ;
for ( size_t i = 0 ; i < sizeof ( try_order ) / sizeof ( __u32 ) ; i + + ) {
2018-11-09 02:27:45 +08:00
palette = try_order [ i ] ;
if ( try_palette_v4l2 ( ) ) {
return true ;
2019-11-23 05:03:52 +08:00
} else if ( errno = = EBUSY ) {
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): device is busy " ) ;
closeDevice ( ) ;
return false ;
2015-10-10 18:39:37 +08:00
}
}
2018-11-09 02:27:45 +08:00
return false ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : setFps ( int value )
2010-05-12 01:44:00 +08:00
{
2018-11-09 02:27:45 +08:00
if ( ! isOpened ( ) )
return false ;
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
v4l2_streamparm streamparm = v4l2_streamparm ( ) ;
streamparm . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
streamparm . parm . capture . timeperframe . numerator = 1 ;
streamparm . parm . capture . timeperframe . denominator = __u32 ( value ) ;
if ( ! tryIoctl ( VIDIOC_S_PARM , & streamparm ) | | ! tryIoctl ( VIDIOC_G_PARM , & streamparm ) )
2019-11-23 05:03:52 +08:00
{
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): can't set FPS: " < < value ) ;
2018-11-09 02:27:45 +08:00
return false ;
2019-11-23 05:03:52 +08:00
}
2010-05-12 01:44:00 +08:00
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): FPS= "
< < streamparm . parm . capture . timeperframe . denominator < < " / "
< < streamparm . parm . capture . timeperframe . numerator ) ;
fps = streamparm . parm . capture . timeperframe . denominator ; // TODO use numerator
2018-11-09 02:27:45 +08:00
return true ;
2015-10-08 22:56:18 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : convertableToRgb ( ) const
2015-10-08 22:56:18 +08:00
{
2018-11-09 02:27:45 +08:00
switch ( palette ) {
2015-11-01 06:48:23 +08:00
case V4L2_PIX_FMT_YVU420 :
2018-08-02 23:34:11 +08:00
case V4L2_PIX_FMT_YUV420 :
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_NV12 :
case V4L2_PIX_FMT_NV21 :
case V4L2_PIX_FMT_YUV411P :
# ifdef HAVE_JPEG
2015-10-11 21:23:47 +08:00
case V4L2_PIX_FMT_MJPEG :
case V4L2_PIX_FMT_JPEG :
2018-11-09 02:27:45 +08:00
# endif
2015-10-11 21:23:47 +08:00
case V4L2_PIX_FMT_YUYV :
case V4L2_PIX_FMT_UYVY :
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_SBGGR8 :
case V4L2_PIX_FMT_SN9C10X :
case V4L2_PIX_FMT_SGBRG8 :
2015-10-25 00:31:57 +08:00
case V4L2_PIX_FMT_RGB24 :
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_Y16 :
2019-07-09 20:00:17 +08:00
case V4L2_PIX_FMT_Y10 :
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_GREY :
case V4L2_PIX_FMT_BGR24 :
return true ;
2015-10-11 21:23:47 +08:00
default :
2018-11-09 02:27:45 +08:00
break ;
2015-10-11 21:23:47 +08:00
}
2018-11-09 02:27:45 +08:00
return false ;
2015-10-11 21:23:47 +08:00
}
2018-11-09 02:27:45 +08:00
void CvCaptureCAM_V4L : : v4l2_create_frame ( )
{
2019-02-26 18:15:59 +08:00
CV_Assert ( form . fmt . pix . width < = ( uint ) std : : numeric_limits < int > : : max ( ) ) ;
CV_Assert ( form . fmt . pix . height < = ( uint ) std : : numeric_limits < int > : : max ( ) ) ;
CvSize size = { ( int ) form . fmt . pix . width , ( int ) form . fmt . pix . height } ;
2015-10-11 21:23:47 +08:00
int channels = 3 ;
2016-09-16 04:13:38 +08:00
int depth = IPL_DEPTH_8U ;
2015-10-11 21:23:47 +08:00
2018-11-09 02:27:45 +08:00
if ( ! convert_rgb ) {
switch ( palette ) {
case V4L2_PIX_FMT_BGR24 :
case V4L2_PIX_FMT_RGB24 :
break ;
case V4L2_PIX_FMT_YUYV :
case V4L2_PIX_FMT_UYVY :
channels = 2 ;
2015-11-01 06:48:23 +08:00
break ;
case V4L2_PIX_FMT_YVU420 :
2018-08-02 23:34:11 +08:00
case V4L2_PIX_FMT_YUV420 :
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_NV12 :
case V4L2_PIX_FMT_NV21 :
channels = 1 ;
2015-11-01 06:48:23 +08:00
size . height = size . height * 3 / 2 ; // "1.5" channels
break ;
2016-09-16 04:13:38 +08:00
case V4L2_PIX_FMT_Y16 :
2019-07-09 20:00:17 +08:00
case V4L2_PIX_FMT_Y10 :
2018-11-09 02:27:45 +08:00
depth = IPL_DEPTH_16U ;
/* fallthru */
case V4L2_PIX_FMT_GREY :
channels = 1 ;
break ;
case V4L2_PIX_FMT_MJPEG :
case V4L2_PIX_FMT_JPEG :
default :
channels = 1 ;
if ( bufferIndex < 0 )
size = cvSize ( buffers [ MAX_V4L_BUFFERS ] . length , 1 ) ;
else
size = cvSize ( buffers [ bufferIndex ] . buffer . bytesused , 1 ) ;
2016-09-16 04:13:38 +08:00
break ;
2015-10-11 21:23:47 +08:00
}
}
/* Set up Image data */
2018-11-09 02:27:45 +08:00
cvInitImageHeader ( & frame , size , depth , channels ) ;
2015-10-11 21:23:47 +08:00
/* Allocate space for pixelformat we convert to.
* If we do not convert frame is just points to the buffer
*/
2018-11-09 02:27:45 +08:00
releaseFrame ( ) ;
// we need memory iff convert_rgb is true
if ( convert_rgb ) {
frame . imageData = ( char * ) cvAlloc ( frame . imageSize ) ;
frame_allocated = true ;
2015-10-11 21:23:47 +08:00
}
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : initCapture ( )
2010-05-12 01:44:00 +08:00
{
2018-11-09 02:27:45 +08:00
if ( ! isOpened ( ) )
return false ;
2018-05-31 18:37:13 +08:00
2019-11-23 05:03:52 +08:00
if ( ! try_init_v4l2 ( ) )
{
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): init failed: errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
/* Find Window info */
2018-11-09 02:27:45 +08:00
form = v4l2_format ( ) ;
form . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2018-05-31 18:37:13 +08:00
2019-11-23 05:03:52 +08:00
if ( ! tryIoctl ( VIDIOC_G_FMT , & form ) )
{
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Could not obtain specifics of capture window (VIDIOC_G_FMT): errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2019-11-23 05:03:52 +08:00
if ( ! autosetup_capture_mode_v4l2 ( ) )
{
if ( errno ! = EBUSY )
{
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Pixel format of incoming image is unsupported by OpenCV " ) ;
2019-11-23 06:10:16 +08:00
}
2018-11-09 02:27:45 +08:00
return false ;
}
2018-05-31 18:37:13 +08:00
/* try to set framerate */
2018-11-09 02:27:45 +08:00
setFps ( fps ) ;
2018-05-31 18:37:13 +08:00
unsigned int min ;
/* Buggy driver paranoia. */
2018-11-09 02:27:45 +08:00
min = form . fmt . pix . width * 2 ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
if ( form . fmt . pix . bytesperline < min )
form . fmt . pix . bytesperline = min ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
min = form . fmt . pix . bytesperline * form . fmt . pix . height ;
if ( form . fmt . pix . sizeimage < min )
form . fmt . pix . sizeimage = min ;
if ( ! requestBuffers ( ) )
return false ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
if ( ! createBuffers ( ) ) {
/* free capture, and returns an error code */
releaseBuffers ( ) ;
return false ;
}
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
v4l2_create_frame ( ) ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
// reinitialize buffers
FirstCapture = true ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
return true ;
} ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : requestBuffers ( )
{
unsigned int buffer_number = bufferSize ;
while ( buffer_number > 0 ) {
2019-11-23 05:03:52 +08:00
if ( requestBuffers ( buffer_number ) & & req . count > = buffer_number )
{
2018-11-09 02:27:45 +08:00
break ;
2019-11-23 05:03:52 +08:00
}
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
buffer_number - - ;
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Insufficient buffer memory -- decreasing buffers: " < < buffer_number ) ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
if ( buffer_number < 1 ) {
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Insufficient buffer memory " ) ;
2018-11-09 02:27:45 +08:00
return false ;
}
bufferSize = req . count ;
return true ;
}
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : requestBuffers ( unsigned int buffer_number )
{
if ( ! isOpened ( ) )
return false ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
req = v4l2_requestbuffers ( ) ;
req . count = buffer_number ;
req . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
req . memory = V4L2_MEMORY_MMAP ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
if ( ! tryIoctl ( VIDIOC_REQBUFS , & req ) ) {
2019-11-23 05:03:52 +08:00
int err = errno ;
if ( EINVAL = = err )
{
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): no support for memory mapping " ) ;
}
else
{
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed VIDIOC_REQBUFS: errno= " < < err < < " ( " < < strerror ( err ) < < " ) " ) ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2019-11-23 05:03:52 +08:00
v4l_buffersRequested = true ;
2018-11-09 02:27:45 +08:00
return true ;
}
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : createBuffers ( )
{
size_t maxLength = 0 ;
for ( unsigned int n_buffers = 0 ; n_buffers < req . count ; + + n_buffers ) {
2018-05-31 18:37:13 +08:00
v4l2_buffer buf = v4l2_buffer ( ) ;
buf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
buf . memory = V4L2_MEMORY_MMAP ;
buf . index = n_buffers ;
2018-11-09 02:27:45 +08:00
if ( ! tryIoctl ( VIDIOC_QUERYBUF , & buf ) ) {
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed VIDIOC_QUERYBUF: errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
buffers [ n_buffers ] . length = buf . length ;
buffers [ n_buffers ] . start =
mmap ( NULL /* start anywhere */ ,
buf . length ,
PROT_READ /* required */ ,
MAP_SHARED /* recommended */ ,
deviceHandle , buf . m . offset ) ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
if ( MAP_FAILED = = buffers [ n_buffers ] . start ) {
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed mmap( " < < buf . length < < " ): errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
maxLength = maxLength > buf . length ? maxLength : buf . length ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
if ( maxLength > 0 ) {
buffers [ MAX_V4L_BUFFERS ] . start = malloc ( maxLength ) ;
buffers [ MAX_V4L_BUFFERS ] . length = maxLength ;
}
return buffers [ MAX_V4L_BUFFERS ] . start ! = 0 ;
}
2010-05-12 01:44:00 +08:00
2015-10-09 22:01:14 +08:00
/**
* some properties can not be changed while the device is in streaming mode .
* this method closes and re - opens the device to re - start the stream .
* this also causes buffers to be reallocated if the frame size was changed .
*/
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : v4l2_reset ( )
{
streaming ( false ) ;
releaseBuffers ( ) ;
return initCapture ( ) ;
2015-10-09 22:01:14 +08:00
}
2015-10-24 20:11:47 +08:00
bool CvCaptureCAM_V4L : : open ( int _index )
2010-05-12 01:44:00 +08:00
{
2018-05-31 19:03:02 +08:00
cv : : String name ;
2018-05-31 18:37:13 +08:00
/* Select camera, or rather, V4L video source */
2018-05-31 19:03:02 +08:00
if ( _index < 0 ) // Asking for the first device available
{
for ( int autoindex = 0 ; autoindex < MAX_CAMERAS ; + + autoindex )
{
name = cv : : format ( " /dev/video%d " , autoindex ) ;
/* Test using an open to see if this new device name really does exists. */
int h = : : open ( name . c_str ( ) , O_RDONLY ) ;
if ( h ! = - 1 )
{
: : close ( h ) ;
_index = autoindex ;
2018-05-31 18:37:13 +08:00
break ;
2018-05-31 19:03:02 +08:00
}
}
if ( _index < 0 )
{
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2): can't find camera device " ) ;
2018-05-31 19:03:02 +08:00
name . clear ( ) ;
2018-05-31 18:37:13 +08:00
return false ;
2018-05-31 19:03:02 +08:00
}
}
else
{
name = cv : : format ( " /dev/video%d " , _index ) ;
2018-05-31 18:37:13 +08:00
}
2018-05-31 19:03:02 +08:00
bool res = open ( name . c_str ( ) ) ;
if ( ! res )
{
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): can't open camera by index " ) ;
2018-05-31 19:03:02 +08:00
}
return res ;
2016-04-12 13:00:37 +08:00
}
2010-05-12 01:44:00 +08:00
2016-04-12 13:00:37 +08:00
bool CvCaptureCAM_V4L : : open ( const char * _deviceName )
{
2019-11-23 05:03:52 +08:00
CV_Assert ( _deviceName ) ;
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < _deviceName < < " ): opening... " ) ;
2018-11-09 02:27:45 +08:00
FirstCapture = true ;
2016-04-12 13:00:37 +08:00
width = DEFAULT_V4L_WIDTH ;
height = DEFAULT_V4L_HEIGHT ;
2018-07-19 16:40:27 +08:00
width_set = height_set = 0 ;
2018-04-09 22:34:00 +08:00
bufferSize = DEFAULT_V4L_BUFFERS ;
2016-04-12 13:00:37 +08:00
fps = DEFAULT_V4L_FPS ;
convert_rgb = true ;
2018-11-09 02:27:45 +08:00
frame_allocated = false ;
2016-04-12 13:00:37 +08:00
deviceName = _deviceName ;
2017-05-23 22:34:35 +08:00
returnFrame = true ;
2018-11-09 02:27:45 +08:00
normalizePropRange = utils : : getConfigurationParameterBool ( " OPENCV_VIDEOIO_V4L_RANGE_NORMALIZED " , true ) ;
channelNumber = - 1 ;
bufferIndex = - 1 ;
deviceHandle = : : open ( deviceName . c_str ( ) , O_RDWR /* required */ | O_NONBLOCK , 0 ) ;
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < _deviceName < < " ): deviceHandle= " < < deviceHandle ) ;
2018-11-09 02:27:45 +08:00
if ( deviceHandle = = - 1 )
return false ;
2016-04-12 13:00:37 +08:00
2018-11-09 02:27:45 +08:00
return initCapture ( ) ;
2015-10-24 20:11:47 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : read_frame_v4l2 ( )
{
2015-10-24 08:07:26 +08:00
v4l2_buffer buf = v4l2_buffer ( ) ;
2010-05-12 01:44:00 +08:00
buf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
buf . memory = V4L2_MEMORY_MMAP ;
2018-11-09 02:27:45 +08:00
while ( ! tryIoctl ( VIDIOC_DQBUF , & buf ) ) {
2019-11-23 05:03:52 +08:00
int err = errno ;
if ( err = = EIO & & ! ( buf . flags & ( V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE ) ) ) {
2018-11-09 02:27:45 +08:00
// Maybe buffer not in the queue? Try to put there
if ( ! tryIoctl ( VIDIOC_QBUF , & buf ) )
return false ;
continue ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
/* display the error and stop processing */
returnFrame = false ;
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): can't read frame (VIDIOC_DQBUF): errno= " < < err < < " ( " < < strerror ( err ) < < " ) " ) ;
2018-11-09 02:27:45 +08:00
return false ;
2018-05-31 18:37:13 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
assert ( buf . index < req . count ) ;
assert ( buffers [ buf . index ] . length = = buf . length ) ;
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
//We shouldn't use this buffer in the queue while not retrieve frame from it.
buffers [ buf . index ] . buffer = buf ;
bufferIndex = buf . index ;
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
//set timestamp in capture struct to be timestamp of most recent frame
2018-11-09 02:27:45 +08:00
timestamp = buf . timestamp ;
return true ;
2010-05-12 01:44:00 +08:00
}
2019-11-23 06:10:16 +08:00
bool CvCaptureCAM_V4L : : tryIoctl ( unsigned long ioctlCode , void * parameter , bool failIfBusy , int attempts ) const
2018-11-09 02:27:45 +08:00
{
2019-11-23 05:03:52 +08:00
CV_Assert ( attempts > 0 ) ;
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): tryIoctl( " < < deviceHandle < < " , "
< < decode_ioctl_code ( ioctlCode ) < < " ( " < < ioctlCode < < " ), failIfBusy= " < < failIfBusy < < " ) "
) ;
while ( true )
{
errno = 0 ;
int result = ioctl ( deviceHandle , ioctlCode , parameter ) ;
int err = errno ;
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): call ioctl( " < < deviceHandle < < " , "
< < decode_ioctl_code ( ioctlCode ) < < " ( " < < ioctlCode < < " ), ...) => "
< < result < < " errno= " < < err < < " ( " < < strerror ( err ) < < " ) "
) ;
if ( result ! = - 1 )
return true ; // success
const bool isBusy = ( err = = EBUSY ) ;
if ( isBusy & & failIfBusy )
{
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): ioctl returns with errno=EBUSY " ) ;
2019-11-23 06:10:16 +08:00
return false ;
}
2019-11-23 05:03:52 +08:00
if ( ! ( isBusy | | errno = = EAGAIN ) )
2019-11-23 06:10:16 +08:00
return false ;
2019-11-23 05:03:52 +08:00
if ( - - attempts = = 0 ) {
2018-11-09 02:27:45 +08:00
return false ;
2019-11-23 05:03:52 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
fd_set fds ;
FD_ZERO ( & fds ) ;
FD_SET ( deviceHandle , & fds ) ;
2010-05-12 01:44:00 +08:00
2018-08-21 00:41:41 +08:00
/* Timeout. */
2019-11-23 05:03:52 +08:00
static int param_v4l_select_timeout = ( int ) utils : : getConfigurationParameterSizeT ( " OPENCV_VIDEOIO_V4L_SELECT_TIMEOUT " , 10 ) ;
2018-11-09 02:27:45 +08:00
struct timeval tv ;
2019-11-23 05:03:52 +08:00
tv . tv_sec = param_v4l_select_timeout ;
2018-08-21 00:41:41 +08:00
tv . tv_usec = 0 ;
2010-05-12 01:44:00 +08:00
2019-11-23 05:03:52 +08:00
errno = 0 ;
result = select ( deviceHandle + 1 , & fds , NULL , NULL , & tv ) ;
err = errno ;
if ( 0 = = result )
{
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): select() timeout. " ) ;
return false ;
}
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): select( " < < deviceHandle < < " ) => "
< < result < < " errno = " < < err < < " ( " < < strerror ( err ) < < " ) "
) ;
if ( EINTR = = err ) // don't loop if signal occurred, like Ctrl+C
{
2018-11-09 02:27:45 +08:00
return false ;
2010-05-12 01:44:00 +08:00
}
}
2018-11-09 02:27:45 +08:00
return true ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : grabFrame ( )
{
if ( FirstCapture ) {
2018-05-31 18:37:13 +08:00
/* Some general initialization must take place the first time through */
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
/* This is just a technicality, but all buffers must be filled up before any
2010-05-12 01:44:00 +08:00
staggered SYNC is applied . SO , filler up . ( see V4L HowTo ) */
2018-11-09 02:27:45 +08:00
bufferIndex = - 1 ;
for ( __u32 index = 0 ; index < req . count ; + + index ) {
v4l2_buffer buf = v4l2_buffer ( ) ;
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
buf . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
buf . memory = V4L2_MEMORY_MMAP ;
buf . index = index ;
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
if ( ! tryIoctl ( VIDIOC_QBUF , & buf ) ) {
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed VIDIOC_QBUF (buffer= " < < index < < " ): errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
2018-05-31 18:37:13 +08:00
return false ;
}
2010-05-12 01:44:00 +08:00
}
2019-11-23 05:03:52 +08:00
if ( ! streaming ( true ) ) {
2018-11-09 02:27:45 +08:00
return false ;
}
2015-10-24 07:45:44 +08:00
# if defined(V4L_ABORT_BADJPEG)
2010-05-12 01:44:00 +08:00
// skip first frame. it is often bad -- this is unnotied in traditional apps,
// but could be fatal if bad jpeg is enabled
2018-11-09 02:27:45 +08:00
if ( ! read_frame_v4l2 ( ) )
2018-05-31 18:37:13 +08:00
return false ;
2010-05-12 01:44:00 +08:00
# endif
2018-05-31 18:37:13 +08:00
/* preparation is ok */
2018-11-09 02:27:45 +08:00
FirstCapture = false ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
// In the case that the grab frame was without retrieveFrame
2019-11-23 05:03:52 +08:00
if ( bufferIndex > = 0 )
{
2018-11-09 02:27:45 +08:00
if ( ! tryIoctl ( VIDIOC_QBUF , & buffers [ bufferIndex ] . buffer ) )
2019-11-23 05:03:52 +08:00
{
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed VIDIOC_QBUF (buffer= " < < bufferIndex < < " ): errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
}
2018-11-09 02:27:45 +08:00
}
return read_frame_v4l2 ( ) ;
2010-05-12 01:44:00 +08:00
}
/*
* Turn a YUV4 : 2 : 0 block into an RGB block
*
* Video4Linux seems to use the blue , green , red channel
* order convention - - rgb [ 0 ] is blue , rgb [ 1 ] is green , rgb [ 2 ] is red .
*
* Color space conversion coefficients taken from the excellent
* http : //www.inforamp.net/~poynton/ColorFAQ.html
* In his terminology , this is a CCIR 601.1 YCbCr - > RGB .
* Y values are given for all 4 pixels , but the U ( Pb )
* and V ( Pr ) are assumed constant over the 2 x2 block .
*
* To avoid floating point arithmetic , the color conversion
* coefficients are scaled into 16.16 fixed - point integers .
* They were determined as follows :
*
* double brightness = 1.0 ; ( 0 - > black ; 1 - > full scale )
* double saturation = 1.0 ; ( 0 - > greyscale ; 1 - > full color )
* double fixScale = brightness * 256 * 256 ;
* int rvScale = ( int ) ( 1.402 * saturation * fixScale ) ;
* int guScale = ( int ) ( - 0.344136 * saturation * fixScale ) ;
* int gvScale = ( int ) ( - 0.714136 * saturation * fixScale ) ;
* int buScale = ( int ) ( 1.772 * saturation * fixScale ) ;
* int yScale = ( int ) ( fixScale ) ;
*/
/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
# define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
static inline void
move_411_block ( int yTL , int yTR , int yBL , int yBR , int u , int v ,
2018-05-31 18:37:13 +08:00
int /*rowPixels*/ , unsigned char * rgb )
2010-05-12 01:44:00 +08:00
{
const int rvScale = 91881 ;
const int guScale = - 22553 ;
const int gvScale = - 46801 ;
const int buScale = 116129 ;
const int yScale = 65536 ;
int r , g , b ;
g = guScale * u + gvScale * v ;
2018-05-31 18:37:13 +08:00
// if (force_rgb) {
// r = buScale * u;
// b = rvScale * v;
// } else {
r = rvScale * v ;
b = buScale * u ;
// }
2010-05-12 01:44:00 +08:00
yTL * = yScale ; yTR * = yScale ;
yBL * = yScale ; yBR * = yScale ;
/* Write out top two first pixels */
rgb [ 0 ] = LIMIT ( b + yTL ) ; rgb [ 1 ] = LIMIT ( g + yTL ) ;
rgb [ 2 ] = LIMIT ( r + yTL ) ;
rgb [ 3 ] = LIMIT ( b + yTR ) ; rgb [ 4 ] = LIMIT ( g + yTR ) ;
rgb [ 5 ] = LIMIT ( r + yTR ) ;
/* Write out top two last pixels */
rgb + = 6 ;
rgb [ 0 ] = LIMIT ( b + yBL ) ; rgb [ 1 ] = LIMIT ( g + yBL ) ;
rgb [ 2 ] = LIMIT ( r + yBL ) ;
rgb [ 3 ] = LIMIT ( b + yBR ) ; rgb [ 4 ] = LIMIT ( g + yBR ) ;
rgb [ 5 ] = LIMIT ( r + yBR ) ;
}
// Consider a YUV411P image of 8x2 pixels.
//
// A plane of Y values as before.
//
// A plane of U values 1 2
// 3 4
//
// A plane of V values 1 2
// 3 4
//
// The U1/V1 samples correspond to the ABCD pixels.
// U2/V2 samples correspond to the EFGH pixels.
//
/* Converts from planar YUV411P to RGB24. */
/* [FD] untested... */
static void
yuv411p_to_rgb24 ( int width , int height ,
2018-05-31 18:37:13 +08:00
unsigned char * pIn0 , unsigned char * pOut0 )
2010-05-12 01:44:00 +08:00
{
const int numpix = width * height ;
const int bytes = 24 > > 3 ;
int i , j , y00 , y01 , y10 , y11 , u , v ;
unsigned char * pY = pIn0 ;
unsigned char * pU = pY + numpix ;
unsigned char * pV = pU + numpix / 4 ;
unsigned char * pOut = pOut0 ;
for ( j = 0 ; j < = height ; j + + ) {
for ( i = 0 ; i < = width - 4 ; i + = 4 ) {
y00 = * pY ;
y01 = * ( pY + 1 ) ;
y10 = * ( pY + 2 ) ;
y11 = * ( pY + 3 ) ;
u = ( * pU + + ) - 128 ;
v = ( * pV + + ) - 128 ;
move_411_block ( y00 , y01 , y10 , y11 , u , v ,
2018-05-31 18:37:13 +08:00
width , pOut ) ;
2010-05-12 01:44:00 +08:00
pY + = 4 ;
pOut + = 4 * bytes ;
}
}
}
/*
* BAYER2RGB24 ROUTINE TAKEN FROM :
*
* Sonix SN9C10x based webcam basic I / F routines
* Takafumi Mizuno < taka - qce @ ls - a . jp >
*
*/
2012-06-09 23:24:36 +08:00
static void bayer2rgb24 ( long int WIDTH , long int HEIGHT , unsigned char * src , unsigned char * dst )
2010-05-12 01:44:00 +08:00
{
long int i ;
unsigned char * rawpt , * scanpt ;
long int size ;
rawpt = src ;
scanpt = dst ;
size = WIDTH * HEIGHT ;
for ( i = 0 ; i < size ; i + + ) {
2018-05-31 18:37:13 +08:00
if ( ( i / WIDTH ) % 2 = = 0 ) {
if ( ( i % 2 ) = = 0 ) {
/* B */
if ( ( i > WIDTH ) & & ( ( i % WIDTH ) > 0 ) ) {
* scanpt + + = ( * ( rawpt - WIDTH - 1 ) + * ( rawpt - WIDTH + 1 ) +
* ( rawpt + WIDTH - 1 ) + * ( rawpt + WIDTH + 1 ) ) / 4 ; /* R */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) +
* ( rawpt + WIDTH ) + * ( rawpt - WIDTH ) ) / 4 ; /* G */
* scanpt + + = * rawpt ; /* B */
} else {
/* first line or left column */
* scanpt + + = * ( rawpt + WIDTH + 1 ) ; /* R */
* scanpt + + = ( * ( rawpt + 1 ) + * ( rawpt + WIDTH ) ) / 2 ; /* G */
* scanpt + + = * rawpt ; /* B */
}
} else {
/* (B)G */
if ( ( i > WIDTH ) & & ( ( i % WIDTH ) < ( WIDTH - 1 ) ) ) {
* scanpt + + = ( * ( rawpt + WIDTH ) + * ( rawpt - WIDTH ) ) / 2 ; /* R */
* scanpt + + = * rawpt ; /* G */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) ) / 2 ; /* B */
} else {
/* first line or right column */
* scanpt + + = * ( rawpt + WIDTH ) ; /* R */
* scanpt + + = * rawpt ; /* G */
* scanpt + + = * ( rawpt - 1 ) ; /* B */
}
}
} else {
if ( ( i % 2 ) = = 0 ) {
/* G(R) */
if ( ( i < ( WIDTH * ( HEIGHT - 1 ) ) ) & & ( ( i % WIDTH ) > 0 ) ) {
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) ) / 2 ; /* R */
* scanpt + + = * rawpt ; /* G */
* scanpt + + = ( * ( rawpt + WIDTH ) + * ( rawpt - WIDTH ) ) / 2 ; /* B */
} else {
/* bottom line or left column */
* scanpt + + = * ( rawpt + 1 ) ; /* R */
* scanpt + + = * rawpt ; /* G */
* scanpt + + = * ( rawpt - WIDTH ) ; /* B */
}
} else {
/* R */
if ( i < ( WIDTH * ( HEIGHT - 1 ) ) & & ( ( i % WIDTH ) < ( WIDTH - 1 ) ) ) {
* scanpt + + = * rawpt ; /* R */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) +
* ( rawpt - WIDTH ) + * ( rawpt + WIDTH ) ) / 4 ; /* G */
* scanpt + + = ( * ( rawpt - WIDTH - 1 ) + * ( rawpt - WIDTH + 1 ) +
* ( rawpt + WIDTH - 1 ) + * ( rawpt + WIDTH + 1 ) ) / 4 ; /* B */
} else {
/* bottom line or right column */
* scanpt + + = * rawpt ; /* R */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt - WIDTH ) ) / 2 ; /* G */
* scanpt + + = * ( rawpt - WIDTH - 1 ) ; /* B */
}
}
}
rawpt + + ;
2010-05-12 01:44:00 +08:00
}
}
// SGBRG to RGB24
// for some reason, red and blue needs to be swapped
// at least for 046d:092f Logitech, Inc. QuickCam Express Plus to work
//see: http://www.siliconimaging.com/RGB%20Bayer.htm
//and 4.6 at http://tldp.org/HOWTO/html_single/libdc1394-HOWTO/
2012-06-09 23:24:36 +08:00
static void sgbrg2rgb24 ( long int WIDTH , long int HEIGHT , unsigned char * src , unsigned char * dst )
2010-05-12 01:44:00 +08:00
{
long int i ;
unsigned char * rawpt , * scanpt ;
long int size ;
rawpt = src ;
scanpt = dst ;
size = WIDTH * HEIGHT ;
for ( i = 0 ; i < size ; i + + )
{
if ( ( i / WIDTH ) % 2 = = 0 ) //even row
{
if ( ( i % 2 ) = = 0 ) //even pixel
{
if ( ( i > WIDTH ) & & ( ( i % WIDTH ) > 0 ) )
{
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) ) / 2 ; /* R */
* scanpt + + = * ( rawpt ) ; /* G */
* scanpt + + = ( * ( rawpt - WIDTH ) + * ( rawpt + WIDTH ) ) / 2 ; /* B */
} else
{
2018-05-31 18:37:13 +08:00
/* first line or left column */
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
* scanpt + + = * ( rawpt + 1 ) ; /* R */
* scanpt + + = * ( rawpt ) ; /* G */
* scanpt + + = * ( rawpt + WIDTH ) ; /* B */
2010-05-12 01:44:00 +08:00
}
} else //odd pixel
{
if ( ( i > WIDTH ) & & ( ( i % WIDTH ) < ( WIDTH - 1 ) ) )
{
* scanpt + + = * ( rawpt ) ; /* R */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) + * ( rawpt - WIDTH ) + * ( rawpt + WIDTH ) ) / 4 ; /* G */
* scanpt + + = ( * ( rawpt - WIDTH - 1 ) + * ( rawpt - WIDTH + 1 ) + * ( rawpt + WIDTH - 1 ) + * ( rawpt + WIDTH + 1 ) ) / 4 ; /* B */
} else
{
/* first line or right column */
* scanpt + + = * ( rawpt ) ; /* R */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + WIDTH ) ) / 2 ; /* G */
* scanpt + + = * ( rawpt + WIDTH - 1 ) ; /* B */
}
}
} else
{ //odd row
if ( ( i % 2 ) = = 0 ) //even pixel
{
if ( ( i < ( WIDTH * ( HEIGHT - 1 ) ) ) & & ( ( i % WIDTH ) > 0 ) )
{
* scanpt + + = ( * ( rawpt - WIDTH - 1 ) + * ( rawpt - WIDTH + 1 ) + * ( rawpt + WIDTH - 1 ) + * ( rawpt + WIDTH + 1 ) ) / 4 ; /* R */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) + * ( rawpt - WIDTH ) + * ( rawpt + WIDTH ) ) / 4 ; /* G */
* scanpt + + = * ( rawpt ) ; /* B */
} else
{
/* bottom line or left column */
* scanpt + + = * ( rawpt - WIDTH + 1 ) ; /* R */
* scanpt + + = ( * ( rawpt + 1 ) + * ( rawpt - WIDTH ) ) / 2 ; /* G */
* scanpt + + = * ( rawpt ) ; /* B */
}
} else
{ //odd pixel
if ( i < ( WIDTH * ( HEIGHT - 1 ) ) & & ( ( i % WIDTH ) < ( WIDTH - 1 ) ) )
{
* scanpt + + = ( * ( rawpt - WIDTH ) + * ( rawpt + WIDTH ) ) / 2 ; /* R */
* scanpt + + = * ( rawpt ) ; /* G */
* scanpt + + = ( * ( rawpt - 1 ) + * ( rawpt + 1 ) ) / 2 ; /* B */
} else
{
/* bottom line or right column */
* scanpt + + = ( * ( rawpt - WIDTH ) ) ; /* R */
* scanpt + + = * ( rawpt ) ; /* G */
* scanpt + + = ( * ( rawpt - 1 ) ) ; /* B */
}
}
}
rawpt + + ;
}
}
# define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))
typedef struct {
2018-05-31 18:37:13 +08:00
int is_abs ;
int len ;
int val ;
2010-05-12 01:44:00 +08:00
} code_table_t ;
/* local storage */
static code_table_t table [ 256 ] ;
static int init_done = 0 ;
/*
sonix_decompress_init
= = = = = = = = = = = = = = = = = = = = =
pre - calculates a locally stored table for efficient huffman - decoding .
Each entry at index x in the table represents the codeword
present at the MSB of byte x .
2018-05-31 18:37:13 +08:00
*/
2012-06-09 23:24:36 +08:00
static void sonix_decompress_init ( void )
2010-05-12 01:44:00 +08:00
{
2018-05-31 18:37:13 +08:00
int i ;
int is_abs , val , len ;
for ( i = 0 ; i < 256 ; i + + ) {
is_abs = 0 ;
val = 0 ;
len = 0 ;
if ( ( i & 0x80 ) = = 0 ) {
/* code 0 */
val = 0 ;
len = 1 ;
}
else if ( ( i & 0xE0 ) = = 0x80 ) {
/* code 100 */
val = + 4 ;
len = 3 ;
}
else if ( ( i & 0xE0 ) = = 0xA0 ) {
/* code 101 */
val = - 4 ;
len = 3 ;
}
else if ( ( i & 0xF0 ) = = 0xD0 ) {
/* code 1101 */
val = + 11 ;
len = 4 ;
}
else if ( ( i & 0xF0 ) = = 0xF0 ) {
/* code 1111 */
val = - 11 ;
len = 4 ;
}
else if ( ( i & 0xF8 ) = = 0xC8 ) {
/* code 11001 */
val = + 20 ;
len = 5 ;
}
else if ( ( i & 0xFC ) = = 0xC0 ) {
/* code 110000 */
val = - 20 ;
len = 6 ;
}
else if ( ( i & 0xFC ) = = 0xC4 ) {
/* code 110001xx: unknown */
val = 0 ;
len = 8 ;
}
else if ( ( i & 0xF0 ) = = 0xE0 ) {
/* code 1110xxxx */
is_abs = 1 ;
val = ( i & 0x0F ) < < 4 ;
len = 8 ;
}
table [ i ] . is_abs = is_abs ;
table [ i ] . val = val ;
table [ i ] . len = len ;
2010-05-12 01:44:00 +08:00
}
2018-05-31 18:37:13 +08:00
init_done = 1 ;
2010-05-12 01:44:00 +08:00
}
/*
sonix_decompress
= = = = = = = = = = = = = = = =
decompresses an image encoded by a SN9C101 camera controller chip .
IN width
height
inp pointer to compressed frame ( with header already stripped )
OUT outp pointer to decompressed frame
Returns 0 if the operation was successful .
Returns < 0 if operation failed .
2018-05-31 18:37:13 +08:00
*/
2012-06-09 23:24:36 +08:00
static int sonix_decompress ( int width , int height , unsigned char * inp , unsigned char * outp )
2010-05-12 01:44:00 +08:00
{
2018-05-31 18:37:13 +08:00
int row , col ;
int val ;
int bitpos ;
unsigned char code ;
unsigned char * addr ;
if ( ! init_done ) {
/* do sonix_decompress_init first! */
return - 1 ;
}
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
bitpos = 0 ;
for ( row = 0 ; row < height ; row + + ) {
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
col = 0 ;
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
/* first two pixels in first two rows are stored as raw 8-bit */
if ( row < 2 ) {
addr = inp + ( bitpos > > 3 ) ;
code = ( addr [ 0 ] < < ( bitpos & 7 ) ) | ( addr [ 1 ] > > ( 8 - ( bitpos & 7 ) ) ) ;
bitpos + = 8 ;
* outp + + = code ;
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
addr = inp + ( bitpos > > 3 ) ;
code = ( addr [ 0 ] < < ( bitpos & 7 ) ) | ( addr [ 1 ] > > ( 8 - ( bitpos & 7 ) ) ) ;
bitpos + = 8 ;
* outp + + = code ;
2010-05-12 01:44:00 +08:00
2018-05-31 18:37:13 +08:00
col + = 2 ;
2010-05-12 01:44:00 +08:00
}
2018-05-31 18:37:13 +08:00
while ( col < width ) {
/* get bitcode from bitstream */
addr = inp + ( bitpos > > 3 ) ;
code = ( addr [ 0 ] < < ( bitpos & 7 ) ) | ( addr [ 1 ] > > ( 8 - ( bitpos & 7 ) ) ) ;
/* update bit position */
bitpos + = table [ code ] . len ;
/* calculate pixel value */
val = table [ code ] . val ;
if ( ! table [ code ] . is_abs ) {
/* value is relative to top and left pixel */
if ( col < 2 ) {
/* left column: relative to top pixel */
val + = outp [ - 2 * width ] ;
}
else if ( row < 2 ) {
/* top row: relative to left pixel */
val + = outp [ - 2 ] ;
}
else {
/* main area: average of left pixel and top pixel */
val + = ( outp [ - 2 ] + outp [ - 2 * width ] ) / 2 ;
}
}
/* store pixel */
* outp + + = CLAMP ( val ) ;
col + + ;
}
2010-05-12 01:44:00 +08:00
}
2018-05-31 18:37:13 +08:00
return 0 ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
void CvCaptureCAM_V4L : : convertToRgb ( const Buffer & currentBuffer )
{
cv : : Size imageSize ( form . fmt . pix . width , form . fmt . pix . height ) ;
// Not found conversion
switch ( palette )
{
case V4L2_PIX_FMT_YUV411P :
yuv411p_to_rgb24 ( imageSize . width , imageSize . height ,
( unsigned char * ) ( currentBuffer . start ) ,
( unsigned char * ) frame . imageData ) ;
return ;
case V4L2_PIX_FMT_SBGGR8 :
bayer2rgb24 ( imageSize . width , imageSize . height ,
( unsigned char * ) currentBuffer . start ,
( unsigned char * ) frame . imageData ) ;
return ;
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_SN9C10X :
sonix_decompress_init ( ) ;
sonix_decompress ( imageSize . width , imageSize . height ,
( unsigned char * ) currentBuffer . start ,
( unsigned char * ) buffers [ MAX_V4L_BUFFERS ] . start ) ;
2015-10-11 21:23:47 +08:00
2018-11-09 02:27:45 +08:00
bayer2rgb24 ( imageSize . width , imageSize . height ,
( unsigned char * ) buffers [ MAX_V4L_BUFFERS ] . start ,
( unsigned char * ) frame . imageData ) ;
return ;
case V4L2_PIX_FMT_SGBRG8 :
sgbrg2rgb24 ( imageSize . width , imageSize . height ,
( unsigned char * ) currentBuffer . start ,
( unsigned char * ) frame . imageData ) ;
return ;
default :
2013-01-29 18:46:13 +08:00
break ;
2018-11-09 02:27:45 +08:00
}
// Converted by cvtColor or imdecode
cv : : Mat destination ( imageSize , CV_8UC3 , frame . imageData ) ;
switch ( palette ) {
2015-10-10 18:26:08 +08:00
case V4L2_PIX_FMT_YVU420 :
2018-11-09 02:27:45 +08:00
cv : : cvtColor ( cv : : Mat ( imageSize . height * 3 / 2 , imageSize . width , CV_8U , currentBuffer . start ) , destination ,
COLOR_YUV2BGR_YV12 ) ;
return ;
2018-08-02 23:34:11 +08:00
case V4L2_PIX_FMT_YUV420 :
2018-11-09 02:27:45 +08:00
cv : : cvtColor ( cv : : Mat ( imageSize . height * 3 / 2 , imageSize . width , CV_8U , currentBuffer . start ) , destination ,
COLOR_YUV2BGR_IYUV ) ;
return ;
case V4L2_PIX_FMT_NV12 :
cv : : cvtColor ( cv : : Mat ( imageSize . height * 3 / 2 , imageSize . width , CV_8U , currentBuffer . start ) , destination ,
COLOR_YUV2RGB_NV12 ) ;
return ;
case V4L2_PIX_FMT_NV21 :
cv : : cvtColor ( cv : : Mat ( imageSize . height * 3 / 2 , imageSize . width , CV_8U , currentBuffer . start ) , destination ,
COLOR_YUV2RGB_NV21 ) ;
return ;
2010-05-12 01:44:00 +08:00
# ifdef HAVE_JPEG
2015-10-10 18:26:08 +08:00
case V4L2_PIX_FMT_MJPEG :
case V4L2_PIX_FMT_JPEG :
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): decoding JPEG frame: size= " < < currentBuffer . buffer . bytesused ) ;
2018-11-09 02:27:45 +08:00
cv : : imdecode ( Mat ( 1 , currentBuffer . buffer . bytesused , CV_8U , currentBuffer . start ) , IMREAD_COLOR , & destination ) ;
return ;
2010-05-12 01:44:00 +08:00
# endif
2015-10-10 18:26:08 +08:00
case V4L2_PIX_FMT_YUYV :
2018-11-09 02:27:45 +08:00
cv : : cvtColor ( cv : : Mat ( imageSize , CV_8UC2 , currentBuffer . start ) , destination , COLOR_YUV2BGR_YUYV ) ;
return ;
2015-10-10 18:26:08 +08:00
case V4L2_PIX_FMT_UYVY :
2018-11-09 02:27:45 +08:00
cv : : cvtColor ( cv : : Mat ( imageSize , CV_8UC2 , currentBuffer . start ) , destination , COLOR_YUV2BGR_UYVY ) ;
return ;
2015-10-10 18:26:08 +08:00
case V4L2_PIX_FMT_RGB24 :
2018-11-09 02:27:45 +08:00
cv : : cvtColor ( cv : : Mat ( imageSize , CV_8UC3 , currentBuffer . start ) , destination , COLOR_RGB2BGR ) ;
return ;
2016-08-30 04:49:02 +08:00
case V4L2_PIX_FMT_Y16 :
2018-11-09 02:27:45 +08:00
{
cv : : Mat temp ( imageSize , CV_8UC1 , buffers [ MAX_V4L_BUFFERS ] . start ) ;
cv : : Mat ( imageSize , CV_16UC1 , currentBuffer . start ) . convertTo ( temp , CV_8U , 1.0 / 256 ) ;
cv : : cvtColor ( temp , destination , COLOR_GRAY2BGR ) ;
return ;
}
2019-07-09 20:00:17 +08:00
case V4L2_PIX_FMT_Y10 :
{
cv : : Mat temp ( imageSize , CV_8UC1 , buffers [ MAX_V4L_BUFFERS ] . start ) ;
cv : : Mat ( imageSize , CV_16UC1 , currentBuffer . start ) . convertTo ( temp , CV_8U , 1.0 / 4 ) ;
cv : : cvtColor ( temp , destination , COLOR_GRAY2BGR ) ;
return ;
}
2018-11-09 02:27:45 +08:00
case V4L2_PIX_FMT_GREY :
cv : : cvtColor ( cv : : Mat ( imageSize , CV_8UC1 , currentBuffer . start ) , destination , COLOR_GRAY2BGR ) ;
break ;
case V4L2_PIX_FMT_BGR24 :
default :
memcpy ( ( char * ) frame . imageData , ( char * ) currentBuffer . start ,
std : : min ( frame . imageSize , ( int ) currentBuffer . buffer . bytesused ) ) ;
2016-08-30 04:49:02 +08:00
break ;
2013-01-29 18:46:13 +08:00
}
2018-11-09 02:27:45 +08:00
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
static inline cv : : String capPropertyName ( int prop )
{
switch ( prop ) {
case cv : : CAP_PROP_POS_MSEC :
return " pos_msec " ;
case cv : : CAP_PROP_POS_FRAMES :
return " pos_frames " ;
case cv : : CAP_PROP_POS_AVI_RATIO :
return " pos_avi_ratio " ;
case cv : : CAP_PROP_FRAME_COUNT :
return " frame_count " ;
case cv : : CAP_PROP_FRAME_HEIGHT :
return " height " ;
case cv : : CAP_PROP_FRAME_WIDTH :
return " width " ;
case cv : : CAP_PROP_CONVERT_RGB :
return " convert_rgb " ;
case cv : : CAP_PROP_FORMAT :
return " format " ;
case cv : : CAP_PROP_MODE :
return " mode " ;
case cv : : CAP_PROP_FOURCC :
return " fourcc " ;
case cv : : CAP_PROP_AUTO_EXPOSURE :
return " auto_exposure " ;
case cv : : CAP_PROP_EXPOSURE :
return " exposure " ;
case cv : : CAP_PROP_TEMPERATURE :
return " temperature " ;
case cv : : CAP_PROP_FPS :
return " fps " ;
case cv : : CAP_PROP_BRIGHTNESS :
return " brightness " ;
case cv : : CAP_PROP_CONTRAST :
return " contrast " ;
case cv : : CAP_PROP_SATURATION :
return " saturation " ;
case cv : : CAP_PROP_HUE :
return " hue " ;
case cv : : CAP_PROP_GAIN :
return " gain " ;
case cv : : CAP_PROP_RECTIFICATION :
return " rectification " ;
case cv : : CAP_PROP_MONOCHROME :
return " monochrome " ;
case cv : : CAP_PROP_SHARPNESS :
return " sharpness " ;
case cv : : CAP_PROP_GAMMA :
return " gamma " ;
case cv : : CAP_PROP_TRIGGER :
return " trigger " ;
case cv : : CAP_PROP_TRIGGER_DELAY :
return " trigger_delay " ;
case cv : : CAP_PROP_WHITE_BALANCE_RED_V :
return " white_balance_red_v " ;
case cv : : CAP_PROP_ZOOM :
return " zoom " ;
case cv : : CAP_PROP_FOCUS :
return " focus " ;
case cv : : CAP_PROP_GUID :
return " guid " ;
case cv : : CAP_PROP_ISO_SPEED :
return " iso_speed " ;
case cv : : CAP_PROP_BACKLIGHT :
return " backlight " ;
case cv : : CAP_PROP_PAN :
return " pan " ;
case cv : : CAP_PROP_TILT :
return " tilt " ;
case cv : : CAP_PROP_ROLL :
return " roll " ;
case cv : : CAP_PROP_IRIS :
return " iris " ;
case cv : : CAP_PROP_SETTINGS :
return " dialog_settings " ;
case cv : : CAP_PROP_BUFFERSIZE :
return " buffersize " ;
case cv : : CAP_PROP_AUTOFOCUS :
return " autofocus " ;
case cv : : CAP_PROP_WHITE_BALANCE_BLUE_U :
return " white_balance_blue_u " ;
case cv : : CAP_PROP_SAR_NUM :
return " sar_num " ;
case cv : : CAP_PROP_SAR_DEN :
return " sar_den " ;
2018-10-26 22:54:00 +08:00
case CAP_PROP_AUTO_WB :
return " auto wb " ;
case CAP_PROP_WB_TEMPERATURE :
return " wb temperature " ;
2018-11-09 02:27:45 +08:00
default :
return " unknown " ;
}
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
static inline int capPropertyToV4L2 ( int prop )
{
2015-10-08 22:56:18 +08:00
switch ( prop ) {
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_FPS :
return - 1 ;
case cv : : CAP_PROP_FOURCC :
return - 1 ;
case cv : : CAP_PROP_FRAME_COUNT :
return V4L2_CID_MPEG_VIDEO_B_FRAMES ;
case cv : : CAP_PROP_FORMAT :
return - 1 ;
case cv : : CAP_PROP_MODE :
return - 1 ;
case cv : : CAP_PROP_BRIGHTNESS :
2015-10-08 22:56:18 +08:00
return V4L2_CID_BRIGHTNESS ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_CONTRAST :
2015-10-08 22:56:18 +08:00
return V4L2_CID_CONTRAST ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_SATURATION :
2015-10-08 22:56:18 +08:00
return V4L2_CID_SATURATION ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_HUE :
2015-10-08 22:56:18 +08:00
return V4L2_CID_HUE ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_GAIN :
2015-10-08 22:56:18 +08:00
return V4L2_CID_GAIN ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_EXPOSURE :
2016-04-12 18:10:54 +08:00
return V4L2_CID_EXPOSURE_ABSOLUTE ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_CONVERT_RGB :
return - 1 ;
case cv : : CAP_PROP_WHITE_BALANCE_BLUE_U :
return V4L2_CID_BLUE_BALANCE ;
case cv : : CAP_PROP_RECTIFICATION :
return - 1 ;
case cv : : CAP_PROP_MONOCHROME :
return - 1 ;
case cv : : CAP_PROP_SHARPNESS :
return V4L2_CID_SHARPNESS ;
case cv : : CAP_PROP_AUTO_EXPOSURE :
return V4L2_CID_EXPOSURE_AUTO ;
case cv : : CAP_PROP_GAMMA :
return V4L2_CID_GAMMA ;
case cv : : CAP_PROP_TEMPERATURE :
return V4L2_CID_WHITE_BALANCE_TEMPERATURE ;
case cv : : CAP_PROP_TRIGGER :
return - 1 ;
case cv : : CAP_PROP_TRIGGER_DELAY :
return - 1 ;
case cv : : CAP_PROP_WHITE_BALANCE_RED_V :
return V4L2_CID_RED_BALANCE ;
case cv : : CAP_PROP_ZOOM :
return V4L2_CID_ZOOM_ABSOLUTE ;
case cv : : CAP_PROP_FOCUS :
2015-10-08 22:56:18 +08:00
return V4L2_CID_FOCUS_ABSOLUTE ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_GUID :
return - 1 ;
case cv : : CAP_PROP_ISO_SPEED :
return V4L2_CID_ISO_SENSITIVITY ;
case cv : : CAP_PROP_BACKLIGHT :
return V4L2_CID_BACKLIGHT_COMPENSATION ;
case cv : : CAP_PROP_PAN :
return V4L2_CID_PAN_ABSOLUTE ;
case cv : : CAP_PROP_TILT :
return V4L2_CID_TILT_ABSOLUTE ;
case cv : : CAP_PROP_ROLL :
return V4L2_CID_ROTATE ;
case cv : : CAP_PROP_IRIS :
return V4L2_CID_IRIS_ABSOLUTE ;
case cv : : CAP_PROP_SETTINGS :
2015-10-08 22:56:18 +08:00
return - 1 ;
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_BUFFERSIZE :
return - 1 ;
case cv : : CAP_PROP_AUTOFOCUS :
return V4L2_CID_FOCUS_AUTO ;
case cv : : CAP_PROP_SAR_NUM :
return V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT ;
case cv : : CAP_PROP_SAR_DEN :
return V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH ;
2018-10-26 22:54:00 +08:00
case CAP_PROP_AUTO_WB :
return V4L2_CID_AUTO_WHITE_BALANCE ;
case CAP_PROP_WB_TEMPERATURE :
return V4L2_CID_WHITE_BALANCE_TEMPERATURE ;
2018-11-09 02:27:45 +08:00
default :
break ;
2015-10-08 22:56:18 +08:00
}
2018-11-09 02:27:45 +08:00
return - 1 ;
2015-10-08 22:56:18 +08:00
}
2018-11-09 02:27:45 +08:00
static inline bool compatibleRange ( int property_id )
{
switch ( property_id ) {
case cv : : CAP_PROP_BRIGHTNESS :
case cv : : CAP_PROP_CONTRAST :
case cv : : CAP_PROP_SATURATION :
case cv : : CAP_PROP_HUE :
case cv : : CAP_PROP_GAIN :
case cv : : CAP_PROP_EXPOSURE :
case cv : : CAP_PROP_FOCUS :
case cv : : CAP_PROP_AUTOFOCUS :
case cv : : CAP_PROP_AUTO_EXPOSURE :
return true ;
default :
break ;
2018-05-31 18:37:13 +08:00
}
2018-11-09 02:27:45 +08:00
return false ;
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : controlInfo ( int property_id , __u32 & _v4l2id , cv : : Range & range ) const
{
2010-05-12 01:44:00 +08:00
/* initialisations */
2018-11-09 02:27:45 +08:00
int v4l2id = capPropertyToV4L2 ( property_id ) ;
v4l2_queryctrl queryctrl = v4l2_queryctrl ( ) ;
queryctrl . id = __u32 ( v4l2id ) ;
if ( v4l2id = = - 1 | | ! tryIoctl ( VIDIOC_QUERYCTRL , & queryctrl ) ) {
2019-11-23 05:03:52 +08:00
CV_LOG_INFO ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): property " < < capPropertyName ( property_id ) < < " is not supported " ) ;
2018-10-16 02:20:15 +08:00
return false ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
_v4l2id = __u32 ( v4l2id ) ;
range = cv : : Range ( queryctrl . minimum , queryctrl . maximum ) ;
if ( normalizePropRange ) {
2018-10-26 22:54:00 +08:00
switch ( property_id )
{
case CAP_PROP_WB_TEMPERATURE :
case CAP_PROP_AUTO_WB :
case CAP_PROP_AUTOFOCUS :
range = Range ( 0 , 1 ) ; // do not convert
break ;
case CAP_PROP_AUTO_EXPOSURE :
2018-11-09 02:27:45 +08:00
range = Range ( 0 , 4 ) ;
2018-10-26 22:54:00 +08:00
default :
break ;
}
2018-11-09 02:27:45 +08:00
}
return true ;
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : icvControl ( __u32 v4l2id , int & value , bool isSet ) const
{
2015-10-24 08:07:26 +08:00
/* set which control we want to set */
2018-11-09 02:27:45 +08:00
v4l2_control control = v4l2_control ( ) ;
control . id = v4l2id ;
control . value = value ;
2010-05-12 01:44:00 +08:00
/* The driver may clamp the value or return ERANGE, ignored here */
2018-11-09 02:27:45 +08:00
if ( ! tryIoctl ( isSet ? VIDIOC_S_CTRL : VIDIOC_G_CTRL , & control ) ) {
2019-11-23 05:03:52 +08:00
int err = errno ;
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed " < < ( isSet ? " VIDIOC_S_CTRL " : " VIDIOC_G_CTRL " ) < < " : errno= " < < err < < " ( " < < strerror ( err ) < < " ) " ) ;
switch ( err ) {
2018-11-09 02:27:45 +08:00
# ifndef NDEBUG
case EINVAL :
fprintf ( stderr ,
" The struct v4l2_control id is invalid or the value is inappropriate for the given control (i.e. "
" if a menu item is selected that is not supported by the driver according to VIDIOC_QUERYMENU). " ) ;
break ;
case ERANGE :
fprintf ( stderr , " The struct v4l2_control value is out of bounds. " ) ;
break ;
case EACCES :
fprintf ( stderr , " Attempt to set a read-only control or to get a write-only control. " ) ;
break ;
# endif
default :
break ;
}
2015-10-24 08:07:26 +08:00
return false ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
if ( ! isSet )
value = control . value ;
return true ;
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
double CvCaptureCAM_V4L : : getProperty ( int property_id ) const
{
switch ( property_id ) {
case cv : : CAP_PROP_FRAME_WIDTH :
return form . fmt . pix . width ;
case cv : : CAP_PROP_FRAME_HEIGHT :
return form . fmt . pix . height ;
case cv : : CAP_PROP_FOURCC :
return palette ;
case cv : : CAP_PROP_FORMAT :
return CV_MAKETYPE ( IPL2CV_DEPTH ( frame . depth ) , frame . nChannels ) ;
case cv : : CAP_PROP_MODE :
if ( normalizePropRange )
return palette ;
return normalizePropRange ;
case cv : : CAP_PROP_CONVERT_RGB :
return convert_rgb ;
case cv : : CAP_PROP_BUFFERSIZE :
return bufferSize ;
case cv : : CAP_PROP_FPS :
{
v4l2_streamparm sp = v4l2_streamparm ( ) ;
sp . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
if ( ! tryIoctl ( VIDIOC_G_PARM , & sp ) ) {
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Unable to get camera FPS " ) ;
2018-11-09 02:27:45 +08:00
return - 1 ;
}
return sp . parm . capture . timeperframe . denominator / ( double ) sp . parm . capture . timeperframe . numerator ;
2016-04-12 18:10:54 +08:00
}
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_POS_MSEC :
if ( FirstCapture )
return 0 ;
2016-04-12 18:10:54 +08:00
2018-11-09 02:27:45 +08:00
return 1000 * timestamp . tv_sec + ( ( double ) timestamp . tv_usec ) / 1000 ;
case cv : : CAP_PROP_CHANNEL :
return channelNumber ;
default :
{
cv : : Range range ;
__u32 v4l2id ;
if ( ! controlInfo ( property_id , v4l2id , range ) )
return - 1.0 ;
int value = 0 ;
if ( ! icvControl ( v4l2id , value , false ) )
return - 1.0 ;
if ( normalizePropRange & & compatibleRange ( property_id ) )
return ( ( double ) value - range . start ) / range . size ( ) ;
return value ;
}
}
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : icvSetFrameSize ( int _width , int _height )
{
if ( _width > 0 )
width_set = _width ;
2018-12-20 07:39:03 +08:00
if ( _height > 0 )
2018-11-09 02:27:45 +08:00
height_set = _height ;
2010-05-12 01:44:00 +08:00
/* two subsequent calls setting WIDTH and HEIGHT will change
the video size */
2018-11-09 02:27:45 +08:00
if ( width_set < = 0 | | height_set < = 0 )
return true ;
width = width_set ;
height = height_set ;
width_set = height_set = 0 ;
return v4l2_reset ( ) ;
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : setProperty ( int property_id , double _value )
{
int value = cvRound ( _value ) ;
2010-05-12 01:44:00 +08:00
switch ( property_id ) {
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_FRAME_WIDTH :
return icvSetFrameSize ( value , 0 ) ;
case cv : : CAP_PROP_FRAME_HEIGHT :
return icvSetFrameSize ( 0 , value ) ;
case cv : : CAP_PROP_FPS :
if ( fps = = static_cast < __u32 > ( value ) )
return true ;
return setFps ( value ) ;
case cv : : CAP_PROP_CONVERT_RGB :
if ( bool ( value ) ) {
convert_rgb = convertableToRgb ( ) ;
return convert_rgb ;
2019-03-12 13:26:51 +08:00
} else {
convert_rgb = false ;
releaseFrame ( ) ;
return true ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_FOURCC :
2018-07-19 16:40:27 +08:00
{
2018-11-09 02:27:45 +08:00
if ( palette = = static_cast < __u32 > ( value ) )
return true ;
__u32 old_palette = palette ;
palette = static_cast < __u32 > ( value ) ;
if ( v4l2_reset ( ) )
return true ;
palette = old_palette ;
v4l2_reset ( ) ;
return false ;
2018-07-19 16:40:27 +08:00
}
2018-11-09 02:27:45 +08:00
case cv : : CAP_PROP_MODE :
normalizePropRange = bool ( value ) ;
return true ;
case cv : : CAP_PROP_BUFFERSIZE :
if ( bufferSize = = value )
return true ;
if ( value > MAX_V4L_BUFFERS | | value < 1 ) {
2019-11-23 05:03:52 +08:00
CV_LOG_WARNING ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): Bad buffer size " < < value < < " , buffer size must be from 1 to " < < MAX_V4L_BUFFERS ) ;
2018-11-09 02:27:45 +08:00
return false ;
}
bufferSize = value ;
return v4l2_reset ( ) ;
case cv : : CAP_PROP_CHANNEL :
2018-05-31 18:37:13 +08:00
{
2018-11-09 02:27:45 +08:00
if ( value < 0 ) {
channelNumber = - 1 ;
return true ;
2016-09-16 04:13:38 +08:00
}
2018-11-09 02:27:45 +08:00
if ( channelNumber = = value )
return true ;
int old_channel = channelNumber ;
channelNumber = value ;
if ( v4l2_reset ( ) )
return true ;
channelNumber = old_channel ;
v4l2_reset ( ) ;
return false ;
2018-05-31 18:37:13 +08:00
}
2015-10-08 22:56:18 +08:00
default :
2018-11-09 02:27:45 +08:00
{
cv : : Range range ;
__u32 v4l2id ;
if ( ! controlInfo ( property_id , v4l2id , range ) )
return false ;
if ( normalizePropRange & & compatibleRange ( property_id ) )
value = cv : : saturate_cast < int > ( _value * range . size ( ) + range . start ) ;
return icvControl ( v4l2id , value , true ) ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
}
return false ;
}
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
void CvCaptureCAM_V4L : : releaseFrame ( )
{
if ( frame_allocated & & frame . imageData ) {
cvFree ( & frame . imageData ) ;
frame_allocated = false ;
}
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
void CvCaptureCAM_V4L : : releaseBuffers ( )
{
releaseFrame ( ) ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
if ( buffers [ MAX_V4L_BUFFERS ] . start ) {
free ( buffers [ MAX_V4L_BUFFERS ] . start ) ;
buffers [ MAX_V4L_BUFFERS ] . start = 0 ;
}
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
bufferIndex = - 1 ;
FirstCapture = true ;
2019-11-23 05:03:52 +08:00
if ( ! v4l_buffersRequested )
2018-11-09 02:27:45 +08:00
return ;
2019-11-23 05:03:52 +08:00
v4l_buffersRequested = false ;
2018-05-31 18:37:13 +08:00
2018-11-09 02:27:45 +08:00
for ( unsigned int n_buffers = 0 ; n_buffers < MAX_V4L_BUFFERS ; + + n_buffers ) {
if ( buffers [ n_buffers ] . start ) {
if ( - 1 = = munmap ( buffers [ n_buffers ] . start , buffers [ n_buffers ] . length ) ) {
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed munmap(): errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
2018-11-09 02:27:45 +08:00
} else {
buffers [ n_buffers ] . start = 0 ;
2018-05-31 18:37:13 +08:00
}
}
}
2018-11-09 02:27:45 +08:00
//Applications can call ioctl VIDIOC_REQBUFS again to change the number of buffers,
// however this cannot succeed when any buffers are still mapped. A count value of zero
// frees all buffers, after aborting or finishing any DMA in progress, an implicit VIDIOC_STREAMOFF.
requestBuffers ( 0 ) ;
2010-05-12 01:44:00 +08:00
} ;
2018-11-09 02:27:45 +08:00
bool CvCaptureCAM_V4L : : streaming ( bool startStream )
2010-05-12 01:44:00 +08:00
{
2019-11-23 05:03:52 +08:00
if ( startStream ! = v4l_streamStarted )
{
if ( ! isOpened ( ) )
{
CV_Assert ( v4l_streamStarted = = false ) ;
return ! startStream ;
}
2010-05-12 01:44:00 +08:00
2019-11-23 05:03:52 +08:00
type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
bool result = tryIoctl ( startStream ? VIDIOC_STREAMON : VIDIOC_STREAMOFF , & type ) ;
if ( result )
{
v4l_streamStarted = startStream ;
return true ;
}
if ( startStream )
{
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed VIDIOC_STREAMON: errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
}
return false ;
}
return startStream ;
2010-05-12 01:44:00 +08:00
}
2018-11-09 02:27:45 +08:00
IplImage * CvCaptureCAM_V4L : : retrieveFrame ( int )
2010-05-12 01:44:00 +08:00
{
2018-11-09 02:27:45 +08:00
if ( bufferIndex < 0 )
return & frame ;
2010-05-12 01:44:00 +08:00
2018-11-09 02:27:45 +08:00
/* Now get what has already been captured as a IplImage return */
const Buffer & currentBuffer = buffers [ bufferIndex ] ;
if ( convert_rgb ) {
if ( ! frame_allocated )
v4l2_create_frame ( ) ;
convertToRgb ( currentBuffer ) ;
} else {
// for mjpeg streams the size might change in between, so we have to change the header
// We didn't allocate memory when not convert_rgb, but we have to recreate the header
2019-11-23 05:03:52 +08:00
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): buffer input size= " < < currentBuffer . buffer . bytesused ) ;
2018-11-09 02:27:45 +08:00
if ( frame . imageSize ! = ( int ) currentBuffer . buffer . bytesused )
v4l2_create_frame ( ) ;
frame . imageData = ( char * ) buffers [ MAX_V4L_BUFFERS ] . start ;
memcpy ( buffers [ MAX_V4L_BUFFERS ] . start , currentBuffer . start ,
std : : min ( buffers [ MAX_V4L_BUFFERS ] . length , ( size_t ) currentBuffer . buffer . bytesused ) ) ;
}
//Revert buffer to the queue
if ( ! tryIoctl ( VIDIOC_QBUF , & buffers [ bufferIndex ] . buffer ) )
2019-11-23 05:03:52 +08:00
{
CV_LOG_DEBUG ( NULL , " VIDEOIO(V4L2: " < < deviceName < < " ): failed VIDIOC_QBUF: errno= " < < errno < < " ( " < < strerror ( errno ) < < " ) " ) ;
}
2018-11-09 02:27:45 +08:00
bufferIndex = - 1 ;
return & frame ;
2010-05-12 01:44:00 +08:00
}
2015-10-24 08:07:26 +08:00
} // end namespace cv
2010-05-12 01:44:00 +08:00
CvCapture * cvCreateCameraCapture_V4L ( int index )
{
2015-10-24 20:11:47 +08:00
cv : : CvCaptureCAM_V4L * capture = new cv : : CvCaptureCAM_V4L ( ) ;
2010-05-12 01:44:00 +08:00
2019-11-23 06:10:16 +08:00
if ( capture - > open ( index ) ) {
2015-10-24 08:07:26 +08:00
return capture ;
2019-11-23 06:10:16 +08:00
}
2010-05-12 01:44:00 +08:00
delete capture ;
2015-10-24 20:11:47 +08:00
return NULL ;
2010-05-12 01:44:00 +08:00
}
2016-04-12 13:00:37 +08:00
CvCapture * cvCreateCameraCapture_V4L ( const char * deviceName )
{
cv : : CvCaptureCAM_V4L * capture = new cv : : CvCaptureCAM_V4L ( ) ;
if ( capture - > open ( deviceName ) )
return capture ;
delete capture ;
return NULL ;
}
2010-05-12 01:44:00 +08:00
# endif