+ p_sys->psz_device = p_sys->psz_vdev = p_sys->psz_adev = NULL;
+ p_sys->fd_video = -1;
+ p_sys->fd_audio = -1;
+
+ ParseMRL( p_input );
+
+ /* Find main device (video or audio) */
+ if( p_sys->psz_device && *p_sys->psz_device )
+ {
+ msg_Dbg( p_input, "main device=`%s'", p_sys->psz_device );
+
+ /* Try to open as video device */
+ p_sys->fd_video = OpenVideoDev( p_input, p_sys->psz_device );
+
+ if( p_sys->fd_video < 0 )
+ {
+ /* Try to open as audio device */
+ p_sys->fd_audio = OpenAudioDev( p_input, p_sys->psz_device );
+ if( p_sys->fd_audio >= 0 )
+ {
+ if( p_sys->psz_adev ) free( p_sys->psz_adev );
+ p_sys->psz_adev = p_sys->psz_device;
+ p_sys->psz_device = NULL;
+ }
+ }
+ else
+ {
+ if( p_sys->psz_vdev ) free( p_sys->psz_vdev );
+ p_sys->psz_vdev = p_sys->psz_device;
+ p_sys->psz_device = NULL;
+ }
+ }
+
+ /* If no device opened, only continue if the access was forced */
+ if( p_sys->fd_video < 0 && p_sys->fd_audio < 0 )
+ {
+ if( !p_input->psz_access ||
+ strcmp( p_input->psz_access, "v4l" ) )
+ {
+ AccessClose( p_this );
+ return VLC_EGENERIC;
+ }
+ }
+
+ /* Find video device */
+ if( p_sys->fd_video < 0 )
+ {
+ if( !p_sys->psz_vdev || !*p_sys->psz_vdev )
+ {
+ var_Create( p_input, "v4l-vdev",
+ VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+ var_Get( p_input, "v4l-vdev", &val );
+
+ if( p_sys->psz_vdev ) free( p_sys->psz_vdev );
+ p_sys->psz_vdev = val.psz_string;
+ }
+
+ if( p_sys->psz_vdev && *p_sys->psz_vdev )
+ {
+ p_sys->fd_video = OpenVideoDev( p_input, p_sys->psz_vdev );
+ }
+ }
+
+ /* Find audio device */
+ if( p_sys->fd_audio < 0 )
+ {
+ if( !p_sys->psz_adev || !*p_sys->psz_adev )
+ {
+ var_Create( p_input, "v4l-adev",
+ VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+ var_Get( p_input, "v4l-adev", &val );
+
+ if( p_sys->psz_adev ) free( p_sys->psz_adev );
+ p_sys->psz_adev = val.psz_string;
+ }
+
+ if( p_sys->psz_adev && *p_sys->psz_adev )
+ {
+ p_sys->fd_audio = OpenAudioDev( p_input, p_sys->psz_adev );
+ }
+ }
+
+ if( p_sys->fd_video < 0 && p_sys->fd_audio < 0 )
+ {
+ AccessClose( p_this );
+ return VLC_EGENERIC;
+ }
+
+ p_input->pf_read = Read;
+ p_input->pf_seek = NULL;
+ p_input->pf_set_area = NULL;
+ p_input->pf_set_program = NULL;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.b_pace_control = 0;
+ p_input->stream.b_seekable = 0;
+ p_input->stream.p_selected_area->i_size = 0;
+ p_input->stream.p_selected_area->i_tell = 0;
+ p_input->stream.i_method = INPUT_METHOD_FILE;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ /* Update default_pts to a suitable value for access */
+ var_Create( p_input, "v4l-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+ var_Get( p_input, "v4l-caching", &val );
+ p_input->i_pts_delay = val.i_int * 1000;
+
+ msg_Info( p_input, "v4l grabbing started" );
+
+ /* create header */
+ p_sys->i_streams = 0;
+ p_sys->i_header_size = 8;
+ p_sys->i_header_pos = 8;
+ p_sys->p_header = malloc( p_sys->i_header_size );
+
+ memcpy( p_sys->p_header, ".v4l", 4 );
+
+ if( p_sys->fd_video >= 0 )
+ {
+ p_sys->i_header_size += 20;
+ p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header_size );
+
+ SetDWBE( &p_sys->p_header[4], ++p_sys->i_streams );
+
+ memcpy( &p_sys->p_header[p_sys->i_header_pos], "vids", 4 );
+ memcpy( &p_sys->p_header[p_sys->i_header_pos+4],
+ &p_sys->i_fourcc, 4 );
+ SetDWBE( &p_sys->p_header[p_sys->i_header_pos+8], p_sys->i_width );
+ SetDWBE( &p_sys->p_header[p_sys->i_header_pos+12], p_sys->i_height );
+ SetDWBE( &p_sys->p_header[p_sys->i_header_pos+16], 0 );
+
+ p_sys->i_header_pos = p_sys->i_header_size;
+ }
+
+ if( p_sys->fd_audio >= 0 )
+ {
+ p_sys->i_header_size += 20;
+ p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header_size );
+
+ SetDWBE( &p_sys->p_header[4], ++p_sys->i_streams );
+
+ memcpy( &p_sys->p_header[p_sys->i_header_pos], "auds", 4 );
+ memcpy( &p_sys->p_header[p_sys->i_header_pos+4], "araw", 4 );
+ SetDWBE( &p_sys->p_header[p_sys->i_header_pos+8],
+ p_sys->b_stereo ? 2 : 1 );
+ SetDWBE( &p_sys->p_header[p_sys->i_header_pos+12],
+ p_sys->i_sample_rate );
+ SetDWBE( &p_sys->p_header[p_sys->i_header_pos+16], 16 );
+
+ p_sys->i_header_pos = p_sys->i_header_size;
+ }
+ p_sys->i_header_pos = 0;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * ParseMRL: parse the options contained in the MRL
+ *****************************************************************************/
+static void ParseMRL( input_thread_t *p_input )
+{
+ access_sys_t *p_sys = p_input->p_access_data;
+
+ char *psz_dup = strdup( p_input->psz_name );
+ char *psz_parser = psz_dup;