mirror of
https://code.videolan.org/videolan/vlc
synced 2024-09-12 13:44:56 +02:00
* Some more probing
* The debug output from a v4l2 capable webcam with this would help...
This commit is contained in:
parent
ba42d61b37
commit
92f7ddf2f9
@ -53,6 +53,10 @@ static void Close( vlc_object_t * );
|
|||||||
#define DEV_LONGTEXT N_( \
|
#define DEV_LONGTEXT N_( \
|
||||||
"Name of the device to use. " \
|
"Name of the device to use. " \
|
||||||
"If you don't specify anything, /dev/video0 will be used.")
|
"If you don't specify anything, /dev/video0 will be used.")
|
||||||
|
#define INPUT_TEXT N_( "Input" )
|
||||||
|
#define INPUT_LONGTEXT N_( \
|
||||||
|
"Input of the card to use (Usually, 0 = tuner, " \
|
||||||
|
"1 = composite, 2 = svideo)." )
|
||||||
|
|
||||||
|
|
||||||
vlc_module_begin();
|
vlc_module_begin();
|
||||||
@ -63,6 +67,8 @@ vlc_module_begin();
|
|||||||
|
|
||||||
add_string( "v4l2-dev", "/dev/video0", 0, DEV_TEXT, DEV_LONGTEXT,
|
add_string( "v4l2-dev", "/dev/video0", 0, DEV_TEXT, DEV_LONGTEXT,
|
||||||
VLC_FALSE );
|
VLC_FALSE );
|
||||||
|
add_integer( "v4l2-input", 0, NULL, INPUT_TEXT, INPUT_LONGTEXT,
|
||||||
|
VLC_TRUE );
|
||||||
|
|
||||||
add_shortcut( "v4l2" );
|
add_shortcut( "v4l2" );
|
||||||
set_capability( "access_demux", 10 );
|
set_capability( "access_demux", 10 );
|
||||||
@ -73,10 +79,13 @@ vlc_module_end();
|
|||||||
* Access: local prototypes
|
* Access: local prototypes
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
static int Demux ( demux_t * );
|
static int DemuxMMAP( demux_t * );
|
||||||
static int Control( demux_t *, int, va_list );
|
static int Control( demux_t *, int, va_list );
|
||||||
|
|
||||||
static int OpenDev( demux_t * );
|
static int ProbeDev( demux_t * );
|
||||||
|
static int OpenVideoDev( demux_t * );
|
||||||
|
|
||||||
|
static block_t *GrabVideo( demux_t * );
|
||||||
|
|
||||||
struct demux_sys_t
|
struct demux_sys_t
|
||||||
{
|
{
|
||||||
@ -88,6 +97,7 @@ struct demux_sys_t
|
|||||||
|
|
||||||
int i_input;
|
int i_input;
|
||||||
struct v4l2_input *p_inputs;
|
struct v4l2_input *p_inputs;
|
||||||
|
int i_selected_input;
|
||||||
|
|
||||||
int i_audio;
|
int i_audio;
|
||||||
/* V4L2 devices cannot have more than 32 audio inputs */
|
/* V4L2 devices cannot have more than 32 audio inputs */
|
||||||
@ -95,6 +105,9 @@ struct demux_sys_t
|
|||||||
|
|
||||||
int i_tuner;
|
int i_tuner;
|
||||||
struct v4l2_tuner *p_tuners;
|
struct v4l2_tuner *p_tuners;
|
||||||
|
|
||||||
|
int i_codec;
|
||||||
|
struct v4l2_fmtdesc *p_codecs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -111,7 +124,6 @@ static int Open( vlc_object_t *p_this )
|
|||||||
demux_sys_t sys;
|
demux_sys_t sys;
|
||||||
|
|
||||||
/* Set up p_demux */
|
/* Set up p_demux */
|
||||||
p_demux->pf_demux = Demux;
|
|
||||||
p_demux->pf_control = Control;
|
p_demux->pf_control = Control;
|
||||||
p_demux->info.i_update = 0;
|
p_demux->info.i_update = 0;
|
||||||
p_demux->info.i_title = 0;
|
p_demux->info.i_title = 0;
|
||||||
@ -123,7 +135,9 @@ static int Open( vlc_object_t *p_this )
|
|||||||
|
|
||||||
p_sys->psz_device = var_CreateGetString( p_demux, "v4l2-dev" );
|
p_sys->psz_device = var_CreateGetString( p_demux, "v4l2-dev" );
|
||||||
|
|
||||||
if( OpenDev( p_demux ) < 0 ) return VLC_EGENERIC;
|
if( ProbeDev( p_demux ) < 0 ) return VLC_EGENERIC;
|
||||||
|
|
||||||
|
if( OpenVideoDev( p_demux ) < 0 ) return VLC_EGENERIC;
|
||||||
|
|
||||||
return VLC_SUCCESS;
|
return VLC_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -136,8 +150,12 @@ static void Close( vlc_object_t *p_this )
|
|||||||
demux_t *p_demux = (demux_t *)p_this;
|
demux_t *p_demux = (demux_t *)p_this;
|
||||||
demux_sys_t *p_sys = p_demux->p_sys;
|
demux_sys_t *p_sys = p_demux->p_sys;
|
||||||
|
|
||||||
|
if( p_sys->i_fd_video >= 0 ) close( p_sys->i_fd_video );
|
||||||
|
|
||||||
if( p_sys->psz_device ) free( p_sys->psz_device );
|
if( p_sys->psz_device ) free( p_sys->psz_device );
|
||||||
if( p_sys->p_inputs ) free( p_sys->p_inputs );
|
if( p_sys->p_inputs ) free( p_sys->p_inputs );
|
||||||
|
if( p_sys->p_tuners ) free( p_sys->p_tuners );
|
||||||
|
if( p_sys->p_codecs ) free( p_sys->p_codecs );
|
||||||
|
|
||||||
free( p_sys );
|
free( p_sys );
|
||||||
}
|
}
|
||||||
@ -152,17 +170,77 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Demux:
|
* Demux:
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
static int Demux( demux_t *p_demux )
|
static int DemuxMMAP( demux_t *p_demux )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* OpenDev: open the device and probe for capabilities
|
* OpenVideoDev: open and set up the video device and probe for capabilities
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
int OpenDev( demux_t *p_demux )
|
int OpenVideoDev( demux_t *p_demux )
|
||||||
{
|
{
|
||||||
int i_device_index;
|
int i_fd;
|
||||||
|
demux_sys_t *p_sys = p_demux->p_sys;
|
||||||
|
|
||||||
|
if( ( i_fd = open( p_sys->psz_device, O_RDWR ) ) < 0 )
|
||||||
|
{
|
||||||
|
msg_Err( p_demux, "cannot open device (%s)", strerror( errno ) );
|
||||||
|
goto open_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_sys->i_fd_video = i_fd;
|
||||||
|
|
||||||
|
if( p_sys->i_selected_input = var_CreateGetInteger( p_demux, "v4l2-input" )
|
||||||
|
> p_sys->i_input )
|
||||||
|
{
|
||||||
|
msg_Warn( p_demux, "invalid input. Using the default one" );
|
||||||
|
p_sys->i_selected_input = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ioctl( i_fd, VIDIOC_S_INPUT, &p_sys->i_selected_input ) < 0 )
|
||||||
|
{
|
||||||
|
msg_Err( p_demux, "cannot set input (%s)", strerror( errno ) );
|
||||||
|
goto open_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p_sys->dev_cap.capabilities & V4L2_CAP_STREAMING )
|
||||||
|
{
|
||||||
|
struct v4l2_requestbuffers reqbuf;
|
||||||
|
|
||||||
|
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
reqbuf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
reqbuf.count = 0;
|
||||||
|
|
||||||
|
if( ioctl( i_fd, VIDIOC_REQBUFS, &reqbuf ) < 0 )
|
||||||
|
{
|
||||||
|
msg_Err( p_demux, "cannot initiate I/O operation (%s). "
|
||||||
|
"Only MMAP is supported at the moment", strerror( errno ) );
|
||||||
|
goto open_failed;
|
||||||
|
}
|
||||||
|
p_demux->pf_demux = DemuxMMAP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg_Warn( p_demux, "I/O method not supported at the moment" );
|
||||||
|
goto open_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VLC_SUCCESS;
|
||||||
|
|
||||||
|
open_failed:
|
||||||
|
if( i_fd ) close( i_fd );
|
||||||
|
p_sys->i_fd_video = 0;
|
||||||
|
return VLC_EGENERIC;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* ProbeDev: probe for capabilities
|
||||||
|
*****************************************************************************/
|
||||||
|
int ProbeDev( demux_t *p_demux )
|
||||||
|
{
|
||||||
|
int i_index;
|
||||||
|
|
||||||
int i_fd;
|
int i_fd;
|
||||||
demux_sys_t *p_sys = p_demux->p_sys;
|
demux_sys_t *p_sys = p_demux->p_sys;
|
||||||
@ -189,14 +267,14 @@ int OpenDev( demux_t *p_demux )
|
|||||||
p_sys->dev_cap.version & 0xFF,
|
p_sys->dev_cap.version & 0xFF,
|
||||||
p_sys->dev_cap.bus_info );
|
p_sys->dev_cap.bus_info );
|
||||||
|
|
||||||
msg_Dbg( p_demux, "The device has the capabilities: (%c) Video Capure, "
|
msg_Dbg( p_demux, "the device has the capabilities: (%c) Video Capure, "
|
||||||
"(%c) Audio, "
|
"(%c) Audio, "
|
||||||
"(%c) Tuner",
|
"(%c) Tuner",
|
||||||
( p_sys->dev_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE ? 'X':' '),
|
( p_sys->dev_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE ? 'X':' '),
|
||||||
( p_sys->dev_cap.capabilities & V4L2_CAP_AUDIO ? 'X':' '),
|
( p_sys->dev_cap.capabilities & V4L2_CAP_AUDIO ? 'X':' '),
|
||||||
( p_sys->dev_cap.capabilities & V4L2_CAP_TUNER ? 'X':' ') );
|
( p_sys->dev_cap.capabilities & V4L2_CAP_TUNER ? 'X':' ') );
|
||||||
|
|
||||||
msg_Dbg( p_demux, "Supported I/O methods are: (%c) Read/Write, "
|
msg_Dbg( p_demux, "supported I/O methods are: (%c) Read/Write, "
|
||||||
"(%c) Streaming, "
|
"(%c) Streaming, "
|
||||||
"(%c) Asynchronous",
|
"(%c) Asynchronous",
|
||||||
( p_sys->dev_cap.capabilities & V4L2_CAP_READWRITE ? 'X':' ' ),
|
( p_sys->dev_cap.capabilities & V4L2_CAP_READWRITE ? 'X':' ' ),
|
||||||
@ -218,20 +296,20 @@ int OpenDev( demux_t *p_demux )
|
|||||||
if( !p_sys->p_inputs ) goto open_failed;
|
if( !p_sys->p_inputs ) goto open_failed;
|
||||||
memset( p_sys->p_inputs, 0, sizeof( struct v4l2_input ) );
|
memset( p_sys->p_inputs, 0, sizeof( struct v4l2_input ) );
|
||||||
|
|
||||||
for( i_device_index = 0; i_device_index < p_sys->i_input; i_device_index++ )
|
for( i_index = 0; i_index < p_sys->i_input; i_index++ )
|
||||||
{
|
{
|
||||||
p_sys->p_inputs[i_device_index].index = i_device_index;
|
p_sys->p_inputs[i_index].index = i_index;
|
||||||
|
|
||||||
if( ioctl( i_fd, VIDIOC_ENUMINPUT, &p_sys->p_inputs[i_device_index] ) )
|
if( ioctl( i_fd, VIDIOC_ENUMINPUT, &p_sys->p_inputs[i_index] ) )
|
||||||
{
|
{
|
||||||
msg_Err( p_demux, "cannot get video input characteristics (%s)",
|
msg_Err( p_demux, "cannot get video input characteristics (%s)",
|
||||||
strerror( errno ) );
|
strerror( errno ) );
|
||||||
goto open_failed;
|
goto open_failed;
|
||||||
}
|
}
|
||||||
msg_Dbg( p_demux, "Video input %i (%s) has type: %s",
|
msg_Dbg( p_demux, "video input %i (%s) has type: %s",
|
||||||
i_device_index,
|
i_index,
|
||||||
p_sys->p_inputs[i_device_index].name,
|
p_sys->p_inputs[i_index].name,
|
||||||
p_sys->p_inputs[i_device_index].type
|
p_sys->p_inputs[i_index].type
|
||||||
== V4L2_INPUT_TYPE_TUNER ?
|
== V4L2_INPUT_TYPE_TUNER ?
|
||||||
"Tuner adapter" :
|
"Tuner adapter" :
|
||||||
"External analog input" );
|
"External analog input" );
|
||||||
@ -239,9 +317,9 @@ int OpenDev( demux_t *p_demux )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* initialize the structures for the ioctls */
|
/* initialize the structures for the ioctls */
|
||||||
for( i_device_index = 0; i_device_index < 32; i_device_index++ )
|
for( i_index = 0; i_index < 32; i_index++ )
|
||||||
{
|
{
|
||||||
p_sys->p_audios[i_device_index].index = i_device_index;
|
p_sys->p_audios[i_index].index = i_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe audio inputs */
|
/* Probe audio inputs */
|
||||||
@ -258,7 +336,7 @@ int OpenDev( demux_t *p_demux )
|
|||||||
goto open_failed;
|
goto open_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_Dbg( p_demux, "Audio device %i (%s) is %s",
|
msg_Dbg( p_demux, "audio device %i (%s) is %s",
|
||||||
p_sys->i_audio,
|
p_sys->i_audio,
|
||||||
p_sys->p_audios[p_sys->i_audio].name,
|
p_sys->p_audios[p_sys->i_audio].name,
|
||||||
p_sys->p_audios[p_sys->i_audio].capability &
|
p_sys->p_audios[p_sys->i_audio].capability &
|
||||||
@ -271,8 +349,7 @@ int OpenDev( demux_t *p_demux )
|
|||||||
|
|
||||||
if( p_sys->dev_cap.capabilities & V4L2_CAP_TUNER )
|
if( p_sys->dev_cap.capabilities & V4L2_CAP_TUNER )
|
||||||
{
|
{
|
||||||
struct v4l2_tuner tuner;
|
struct v4l2_tuner tuner = {};
|
||||||
memset( &tuner, 0, sizeof( struct v4l2_tuner ) );
|
|
||||||
|
|
||||||
while( ioctl( i_fd, VIDIOC_S_TUNER, &tuner ) >= 0 )
|
while( ioctl( i_fd, VIDIOC_S_TUNER, &tuner ) >= 0 )
|
||||||
{
|
{
|
||||||
@ -284,34 +361,71 @@ int OpenDev( demux_t *p_demux )
|
|||||||
if( !p_sys->p_tuners ) goto open_failed;
|
if( !p_sys->p_tuners ) goto open_failed;
|
||||||
memset( p_sys->p_tuners, 0, sizeof( struct v4l2_tuner ) );
|
memset( p_sys->p_tuners, 0, sizeof( struct v4l2_tuner ) );
|
||||||
|
|
||||||
for( i_device_index = 0; i_device_index < p_sys->i_tuner; i_device_index++ )
|
for( i_index = 0; i_index < p_sys->i_tuner; i_index++ )
|
||||||
{
|
{
|
||||||
p_sys->p_tuners[i_device_index].index = i_device_index;
|
p_sys->p_tuners[i_index].index = i_index;
|
||||||
|
|
||||||
if( ioctl( i_fd, VIDIOC_G_TUNER, &p_sys->p_tuners[i_device_index] ) )
|
if( ioctl( i_fd, VIDIOC_G_TUNER, &p_sys->p_tuners[i_index] ) )
|
||||||
{
|
{
|
||||||
msg_Err( p_demux, "cannot get tuner characteristics (%s)",
|
msg_Err( p_demux, "cannot get tuner characteristics (%s)",
|
||||||
strerror( errno ) );
|
strerror( errno ) );
|
||||||
goto open_failed;
|
goto open_failed;
|
||||||
}
|
}
|
||||||
msg_Dbg( p_demux, "Tuner %i (%s) has type: %s, "
|
msg_Dbg( p_demux, "tuner %i (%s) has type: %s, "
|
||||||
"frequency range: %.1f %s -> %.1f %s",
|
"frequency range: %.1f %s -> %.1f %s",
|
||||||
i_device_index,
|
i_index,
|
||||||
p_sys->p_tuners[i_device_index].name,
|
p_sys->p_tuners[i_index].name,
|
||||||
p_sys->p_tuners[i_device_index].type
|
p_sys->p_tuners[i_index].type
|
||||||
== V4L2_TUNER_RADIO ?
|
== V4L2_TUNER_RADIO ?
|
||||||
"Radio" : "Analog TV",
|
"Radio" : "Analog TV",
|
||||||
p_sys->p_tuners[i_device_index].rangelow * 62.5,
|
p_sys->p_tuners[i_index].rangelow * 62.5,
|
||||||
p_sys->p_tuners[i_device_index].capability &
|
p_sys->p_tuners[i_index].capability &
|
||||||
V4L2_TUNER_CAP_LOW ?
|
V4L2_TUNER_CAP_LOW ?
|
||||||
"Hz" : "kHz",
|
"Hz" : "kHz",
|
||||||
p_sys->p_tuners[i_device_index].rangehigh * 62.5,
|
p_sys->p_tuners[i_index].rangehigh * 62.5,
|
||||||
p_sys->p_tuners[i_device_index].capability &
|
p_sys->p_tuners[i_index].capability &
|
||||||
V4L2_TUNER_CAP_LOW ?
|
V4L2_TUNER_CAP_LOW ?
|
||||||
"Hz" : "kHz" );
|
"Hz" : "kHz" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Probe for available chromas */
|
||||||
|
if( p_sys->dev_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE )
|
||||||
|
{
|
||||||
|
struct v4l2_fmtdesc codec = {};
|
||||||
|
|
||||||
|
i_index = 0;
|
||||||
|
codec.index = i_index;
|
||||||
|
codec.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
|
while( ioctl( i_fd, VIDIOC_ENUM_FMT, &codec ) >= 0 )
|
||||||
|
{
|
||||||
|
i_index++;
|
||||||
|
codec.index = i_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_sys->i_codec = i_index;
|
||||||
|
|
||||||
|
p_sys->p_codecs = malloc( p_sys->i_codec * sizeof( struct v4l2_fmtdesc ) );
|
||||||
|
memset( p_sys->p_codecs, 0, p_sys->i_codec * sizeof( struct v4l2_fmtdesc ) );
|
||||||
|
|
||||||
|
for( i_index = 0; i_index < p_sys->i_codec; i_index++ )
|
||||||
|
{
|
||||||
|
p_sys->p_codecs[i_index].index = i_index;
|
||||||
|
p_sys->p_codecs[i_index].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
|
if( ioctl( i_fd, VIDIOC_ENUM_FMT, &p_sys->p_codecs[i_index] ) < 0 )
|
||||||
|
{
|
||||||
|
msg_Err( p_demux, "cannot get codec description (%s)", strerror( errno ) );
|
||||||
|
goto open_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_Dbg( p_demux, "device supports Codec %s",
|
||||||
|
p_sys->p_codecs[i_index].description );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if( i_fd >= 0 ) close( i_fd );
|
if( i_fd >= 0 ) close( i_fd );
|
||||||
return VLC_SUCCESS;
|
return VLC_SUCCESS;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user