v4l.c 52.4 KB
Newer Older
1 2 3
/*****************************************************************************
 * v4l.c : Video4Linux input module for vlc
 *****************************************************************************
4
 * Copyright (C) 2002-2004 the VideoLAN team
5
 * $Id$
6
 *
Sam Hocevar's avatar
Sam Hocevar committed
7
 * Author: Laurent Aimar <fenrir@via.ecp.fr>
8
 *         Paul Forgey <paulf at aphrodite dot com>
9
 *         Gildas Bazin <gbazin@videolan.org>
Benjamin Pracht's avatar
Benjamin Pracht committed
10
 *         Benjamin Pracht <bigben at videolan dot org>
11 12 13 14 15
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
16
 *
17 18 19 20 21 22 23
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 26 27 28 29
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
30

31 32 33 34
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

35
#include <vlc_common.h>
36
#include <vlc_plugin.h>
Clément Stenac's avatar
Round 2  
Clément Stenac committed
37 38 39 40
#include <vlc_input.h>
#include <vlc_demux.h>
#include <vlc_access.h>
#include <vlc_vout.h>
Clément Stenac's avatar
Clément Stenac committed
41
#include <vlc_codecs.h>
42 43 44

#include <sys/types.h>
#include <sys/stat.h>
45 46 47 48
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
49
#include <fcntl.h>
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

/* From GStreamer's v4l plugin:
 * Because of some really cool feature in video4linux1, also known as
 * 'not including sys/types.h and sys/time.h', we had to include it
 * ourselves. In all their intelligence, these people decided to fix
 * this in the next version (video4linux2) in such a cool way that it
 * breaks all compilations of old stuff...
 * The real problem is actually that linux/time.h doesn't use proper
 * macro checks before defining types like struct timeval. The proper
 * fix here is to either fuck the kernel header (which is what we do
 * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it
 * upstream, which I'll consider doing later on. If you get compiler
 * errors here, check your linux/time.h && sys/time.h header setup.
*/
#define _LINUX_TIME_H

66
#include <linux/videodev.h>
67
#include "videodev_mjpeg.h"
68

69
#include <sys/soundcard.h>
70 71

/*****************************************************************************
72
 * Module descriptior
73
 *****************************************************************************/
74 75
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
76

Christophe Massiot's avatar
Christophe Massiot committed
77
#define CACHING_TEXT N_("Caching value in ms")
78
#define CACHING_LONGTEXT N_( \
79
    "Caching value for V4L captures. This " \
Clément Stenac's avatar
Clément Stenac committed
80
    "value should be set in milliseconds." )
Gildas Bazin's avatar
 
Gildas Bazin committed
81 82
#define VDEV_TEXT N_("Video device name")
#define VDEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
83
    "Name of the video device to use. " \
Gildas Bazin's avatar
 
Gildas Bazin committed
84 85 86
    "If you don't specify anything, no video device will be used.")
#define ADEV_TEXT N_("Audio device name")
#define ADEV_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
87
    "Name of the audio device to use. " \
88
    "If you don't specify anything, no audio device will be used.")
Gildas Bazin's avatar
 
Gildas Bazin committed
89 90
#define CHROMA_TEXT N_("Video input chroma format")
#define CHROMA_LONGTEXT N_( \
91 92
    "Force the Video4Linux video device to use a specific chroma format " \
    "(eg. I420 (default), RV24, etc.)")
Benjamin Pracht's avatar
Benjamin Pracht committed
93 94
#define FREQUENCY_TEXT N_( "Frequency" )
#define FREQUENCY_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
95
    "Frequency to capture (in kHz), if applicable." )
Benjamin Pracht's avatar
Benjamin Pracht committed
96 97 98
#define CHANNEL_TEXT N_( "Channel" )
#define CHANNEL_LONGTEXT N_( \
    "Channel of the card to use (Usually, 0 = tuner, " \
Clément Stenac's avatar
Clément Stenac committed
99
    "1 = composite, 2 = svideo)." )
Benjamin Pracht's avatar
Benjamin Pracht committed
100 101
#define NORM_TEXT N_( "Norm" )
#define NORM_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
102
    "Norm of the stream (Automatic, SECAM, PAL, or NTSC)." )
Benjamin Pracht's avatar
Benjamin Pracht committed
103 104
#define AUDIO_TEXT N_( "Audio Channel" )
#define AUDIO_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
105
    "Audio Channel to use, if there are several audio inputs." )
Benjamin Pracht's avatar
Benjamin Pracht committed
106 107
#define WIDTH_TEXT N_( "Width" )
#define WIDTH_LONGTEXT N_( "Width of the stream to capture " \
Clément Stenac's avatar
Clément Stenac committed
108
    "(-1 for autodetect)." )
Benjamin Pracht's avatar
Benjamin Pracht committed
109 110
#define HEIGHT_TEXT N_( "Height" )
#define HEIGHT_LONGTEXT N_( "Height of the stream to capture " \
Clément Stenac's avatar
Clément Stenac committed
111
    "(-1 for autodetect)." )
Benjamin Pracht's avatar
Benjamin Pracht committed
112 113
#define BRIGHTNESS_TEXT N_( "Brightness" )
#define BRIGHTNESS_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
114
    "Brightness of the video input." )
Benjamin Pracht's avatar
Benjamin Pracht committed
115 116
#define HUE_TEXT N_( "Hue" )
#define HUE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
117
    "Hue of the video input." )
118
#define COLOUR_TEXT N_( "Color" )
Benjamin Pracht's avatar
Benjamin Pracht committed
119
#define COLOUR_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
120
    "Color of the video input." )
Benjamin Pracht's avatar
Benjamin Pracht committed
121 122
#define CONTRAST_TEXT N_( "Contrast" )
#define CONTRAST_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
123
    "Contrast of the video input." )
Benjamin Pracht's avatar
Benjamin Pracht committed
124
#define TUNER_TEXT N_( "Tuner" )
Clément Stenac's avatar
Clément Stenac committed
125
#define TUNER_LONGTEXT N_( "Tuner to use, if there are several ones." )
Benjamin Pracht's avatar
Benjamin Pracht committed
126 127
#define SAMPLERATE_TEXT N_( "Samplerate" )
#define SAMPLERATE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
128
    "Samplerate of the captured audio stream, in Hz (eg: 11025, 22050, 44100)" )
Benjamin Pracht's avatar
Benjamin Pracht committed
129 130
#define STEREO_TEXT N_( "Stereo" )
#define STEREO_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
131
    "Capture the audio stream in stereo." )
Benjamin Pracht's avatar
Benjamin Pracht committed
132 133 134 135 136
#define MJPEG_TEXT N_( "MJPEG" )
#define MJPEG_LONGTEXT N_(  \
    "Set this option if the capture device outputs MJPEG" )
#define DECIMATION_TEXT N_( "Decimation" )
#define DECIMATION_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
137
    "Decimation level for MJPEG streams" )
Benjamin Pracht's avatar
Benjamin Pracht committed
138
#define QUALITY_TEXT N_( "Quality" )
Clément Stenac's avatar
Clément Stenac committed
139
#define QUALITY_LONGTEXT N_( "Quality of the stream." )
Benjamin Pracht's avatar
Benjamin Pracht committed
140 141
#define FPS_TEXT N_( "Framerate" )
#define FPS_LONGTEXT N_( "Framerate to capture, if applicable " \
Clément Stenac's avatar
Clément Stenac committed
142
    "(-1 for autodetect)." )
143

144 145
static int i_norm_list[] =
    { VIDEO_MODE_AUTO, VIDEO_MODE_SECAM, VIDEO_MODE_PAL, VIDEO_MODE_NTSC };
146
static const char *const psz_norm_list_text[] =
147 148
    { N_("Automatic"), N_("SECAM"), N_("PAL"),  N_("NTSC") };

149
vlc_module_begin();
150 151
    set_shortname( N_("Video4Linux") );
    set_description( N_("Video4Linux input") );
Clément Stenac's avatar
Clément Stenac committed
152 153
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACCESS );
Gildas Bazin's avatar
 
Gildas Bazin committed
154

Gildas Bazin's avatar
 
Gildas Bazin committed
155
    add_integer( "v4l-caching", DEFAULT_PTS_DELAY / 1000, NULL,
156
                 CACHING_TEXT, CACHING_LONGTEXT, true );
Gildas Bazin's avatar
 
Gildas Bazin committed
157
    add_string( "v4l-vdev", "/dev/video", 0, VDEV_TEXT, VDEV_LONGTEXT,
158
                false );
Gildas Bazin's avatar
 
Gildas Bazin committed
159
    add_string( "v4l-adev", "/dev/dsp", 0, ADEV_TEXT, ADEV_LONGTEXT,
160
                false );
Gildas Bazin's avatar
 
Gildas Bazin committed
161
    add_string( "v4l-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
162 163
                true );
    add_float( "v4l-fps", -1.0, NULL, FPS_TEXT, FPS_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
164
    add_integer( "v4l-samplerate", 44100, NULL, SAMPLERATE_TEXT,
165
                SAMPLERATE_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
166
    add_integer( "v4l-channel", 0, NULL, CHANNEL_TEXT, CHANNEL_LONGTEXT,
167 168
                true );
    add_integer( "v4l-tuner", -1, NULL, TUNER_TEXT, TUNER_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
169
    add_integer( "v4l-norm", VIDEO_MODE_AUTO, NULL, NORM_TEXT, NORM_LONGTEXT,
170
                false );
171
        change_integer_list( i_norm_list, psz_norm_list_text, 0 );
Benjamin Pracht's avatar
Benjamin Pracht committed
172
    add_integer( "v4l-frequency", -1, NULL, FREQUENCY_TEXT, FREQUENCY_LONGTEXT,
173 174 175 176 177
                false );
    add_integer( "v4l-audio", -1, NULL, AUDIO_TEXT, AUDIO_LONGTEXT, true );
    add_bool( "v4l-stereo", true, NULL, STEREO_TEXT, STEREO_LONGTEXT,
            true );
    add_integer( "v4l-width", 0, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
178
    add_integer( "v4l-height", 0, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT,
179
                true );
Benjamin Pracht's avatar
Benjamin Pracht committed
180
    add_integer( "v4l-brightness", -1, NULL, BRIGHTNESS_TEXT,
181
                BRIGHTNESS_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
182
    add_integer( "v4l-colour", -1, NULL, COLOUR_TEXT, COLOUR_LONGTEXT,
183 184
                true );
    add_integer( "v4l-hue", -1, NULL, HUE_TEXT, HUE_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
185
    add_integer( "v4l-contrast", -1, NULL, CONTRAST_TEXT, CONTRAST_LONGTEXT,
186 187 188
                true );
    add_bool( "v4l-mjpeg", false, NULL, MJPEG_TEXT, MJPEG_LONGTEXT,
            true );
Benjamin Pracht's avatar
Benjamin Pracht committed
189
    add_integer( "v4l-decimation", 1, NULL, DECIMATION_TEXT,
190
            DECIMATION_LONGTEXT, true );
Benjamin Pracht's avatar
Benjamin Pracht committed
191
    add_integer( "v4l-quality", 100, NULL, QUALITY_TEXT, QUALITY_LONGTEXT,
192
            true );
Gildas Bazin's avatar
 
Gildas Bazin committed
193

Gildas Bazin's avatar
 
Gildas Bazin committed
194
    add_shortcut( "v4l" );
195 196
    set_capability( "access_demux", 10 );
    set_callbacks( Open, Close );
197 198
vlc_module_end();

199 200 201
/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/
202 203
static int Demux  ( demux_t * );
static int Control( demux_t *, int, va_list );
204

205 206 207
static void ParseMRL    ( demux_t * );
static int  OpenVideoDev( demux_t *, char * );
static int  OpenAudioDev( demux_t *, char * );
208

209 210
static block_t *GrabAudio( demux_t * );
static block_t *GrabVideo( demux_t * );
211

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
#define MJPEG_BUFFER_SIZE (256*1024)

struct quicktime_mjpeg_app1
{
    uint32_t    i_reserved;             /* set to 0 */
    uint32_t    i_tag;                  /* 'mjpg' */
    uint32_t    i_field_size;           /* offset following EOI */
    uint32_t    i_padded_field_size;    /* offset following EOI+pad */
    uint32_t    i_next_field;           /* offset to next field */
    uint32_t    i_DQT_offset;
    uint32_t    i_DHT_offset;
    uint32_t    i_SOF_offset;
    uint32_t    i_SOS_offset;
    uint32_t    i_data_offset;          /* following SOS marker data */
};

Gildas Bazin's avatar
 
Gildas Bazin committed
228 229 230 231 232 233 234 235 236 237 238 239 240
static struct
{
    int i_v4l;
    int i_fourcc;

} v4lchroma_to_fourcc[] =
{
    { VIDEO_PALETTE_GREY, VLC_FOURCC( 'G', 'R', 'E', 'Y' ) },
    { VIDEO_PALETTE_HI240, VLC_FOURCC( 'I', '2', '4', '0' ) },
    { VIDEO_PALETTE_RGB565, VLC_FOURCC( 'R', 'V', '1', '6' ) },
    { VIDEO_PALETTE_RGB555, VLC_FOURCC( 'R', 'V', '1', '5' ) },
    { VIDEO_PALETTE_RGB24, VLC_FOURCC( 'R', 'V', '2', '4' ) },
    { VIDEO_PALETTE_RGB32, VLC_FOURCC( 'R', 'V', '3', '2' ) },
241 242 243
    { VIDEO_PALETTE_YUV422, VLC_FOURCC( 'Y', 'U', 'Y', '2' ) },
    { VIDEO_PALETTE_YUV422, VLC_FOURCC( 'Y', 'U', 'Y', 'V' ) },
    { VIDEO_PALETTE_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', '2' ) },
Gildas Bazin's avatar
 
Gildas Bazin committed
244 245 246 247 248 249 250 251 252 253 254
    { VIDEO_PALETTE_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', 'V' ) },
    { VIDEO_PALETTE_UYVY, VLC_FOURCC( 'U', 'Y', 'V', 'Y' ) },
    { VIDEO_PALETTE_YUV420, VLC_FOURCC( 'I', '4', '2', 'N' ) },
    { VIDEO_PALETTE_YUV411, VLC_FOURCC( 'I', '4', '1', 'N' ) },
    { VIDEO_PALETTE_RAW, VLC_FOURCC( 'G', 'R', 'A', 'W' ) },
    { VIDEO_PALETTE_YUV422P, VLC_FOURCC( 'I', '4', '2', '2' ) },
    { VIDEO_PALETTE_YUV420P, VLC_FOURCC( 'I', '4', '2', '0' ) },
    { VIDEO_PALETTE_YUV411P, VLC_FOURCC( 'I', '4', '1', '1' ) },
    { 0, 0 }
};

255
struct demux_sys_t
256
{
Gildas Bazin's avatar
 
Gildas Bazin committed
257 258
    /* Devices */
    char *psz_device;         /* Main device from MRL, can be video or audio */
259

Gildas Bazin's avatar
 
Gildas Bazin committed
260 261 262 263 264 265 266 267
    char *psz_vdev;
    int  fd_video;

    char *psz_adev;
    int  fd_audio;

    /* Video properties */
    picture_t pic;
268

Gildas Bazin's avatar
 
Gildas Bazin committed
269
    int i_fourcc;
270 271 272 273 274 275 276 277
    int i_channel;
    int i_audio;
    int i_norm;
    int i_tuner;
    int i_frequency;
    int i_width;
    int i_height;

278 279 280 281 282
    int i_brightness;
    int i_hue;
    int i_colour;
    int i_contrast;

283 284 285
    float f_fps;            /* <= 0.0 mean to grab at full rate */
    mtime_t i_video_pts;    /* only used when f_fps > 0 */

286
    bool b_mjpeg;
287 288 289
    int i_decimation;
    int i_quality;

290 291
    struct video_capability vid_cap;
    struct video_mbuf       vid_mbuf;
292
    struct mjpeg_requestbuffers mjpeg_buffers;
293 294 295

    uint8_t *p_video_mmap;
    int     i_frame_pos;
296

297
    struct video_mmap   vid_mmap;
Gildas Bazin's avatar
 
Gildas Bazin committed
298
    struct video_picture vid_picture;
299

300 301
    int          i_video_frame_size;
    es_out_id_t  *p_es_video;
302

Gildas Bazin's avatar
 
Gildas Bazin committed
303
    /* Audio properties */
304 305
    vlc_fourcc_t i_acodec_raw;
    int          i_sample_rate;
306
    bool   b_stereo;
307 308 309
    int          i_audio_max_frame_size;
    block_t      *p_block_audio;
    es_out_id_t  *p_es_audio;
310 311
};

312
/*****************************************************************************
313
 * Open: opens v4l device
314 315 316 317
 *****************************************************************************
 *
 * url: <video device>::::
 *
318
 *****************************************************************************/
319
static int Open( vlc_object_t *p_this )
320
{
321 322
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;
323
    vlc_value_t val;
324

325 326 327 328
    /* Only when selected */
    if( *p_demux->psz_access == '\0' )
        return VLC_EGENERIC;

329 330 331 332 333 334 335 336
    /* Set up p_demux */
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;
    p_demux->info.i_update = 0;
    p_demux->info.i_title = 0;
    p_demux->info.i_seekpoint = 0;
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
    memset( p_sys, 0, sizeof( demux_sys_t ) );
337

338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
    var_Create( p_demux, "v4l-audio", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-audio", &val );
    p_sys->i_audio          = val.i_int;

    var_Create( p_demux, "v4l-channel", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-channel", &val );
    p_sys->i_channel        = val.i_int;

    var_Create( p_demux, "v4l-norm", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-norm", &val );
    p_sys->i_norm           = val.i_int;

    var_Create( p_demux, "v4l-tuner", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-tuner", &val );
    p_sys->i_tuner          = val.i_int;

    var_Create( p_demux, "v4l-frequency",
                                    VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-frequency", &val );
    p_sys->i_frequency      = val.i_int;

    var_Create( p_demux, "v4l-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-fps", &val );
    p_sys->f_fps            = val.f_float;

    var_Create( p_demux, "v4l-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-width", &val );
    p_sys->i_width          = val.i_int;

    var_Create( p_demux, "v4l-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-height", &val );
Laurent Aimar's avatar
Laurent Aimar committed
369
    p_sys->i_height         = val.i_int;
370

371 372
    p_sys->i_video_pts      = -1;

373 374
    var_Create( p_demux, "v4l-brightness", VLC_VAR_INTEGER |
                                                        VLC_VAR_DOINHERIT );
Benjamin Pracht's avatar
Benjamin Pracht committed
375
    var_Get( p_demux, "v4l-brightness", &val );
376 377 378 379
    p_sys->i_brightness     = val.i_int;

    var_Create( p_demux, "v4l-hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-hue", &val );
380 381
    p_sys->i_hue            = -1;

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    var_Create( p_demux, "v4l-colour", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-colour", &val );
    p_sys->i_colour         = val.i_int;

    var_Create( p_demux, "v4l-contrast", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-contrast", &val );
    p_sys->i_contrast       = val.i_int;

    var_Create( p_demux, "v4l-mjpeg", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-mjpeg", &val );
    p_sys->b_mjpeg     = val.b_bool;

    var_Create( p_demux, "v4l-decimation", VLC_VAR_INTEGER |
                                                            VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-decimation", &val );
    p_sys->i_decimation = val.i_int;

    var_Create( p_demux, "v4l-quality", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-quality", &val );
    p_sys->i_quality = val.i_int;

    var_Create( p_demux, "v4l-samplerate",
                                    VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-samplerate", &val );
    p_sys->i_sample_rate  = val.i_int;
407

408 409 410
    var_Create( p_demux, "v4l-stereo", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_demux, "v4l-stereo", &val );
    p_sys->b_stereo       = val.b_bool;
411

Gildas Bazin's avatar
 
Gildas Bazin committed
412 413 414 415
    p_sys->psz_device = p_sys->psz_vdev = p_sys->psz_adev = NULL;
    p_sys->fd_video = -1;
    p_sys->fd_audio = -1;

416 417 418 419
    p_sys->p_es_video = p_sys->p_es_audio = 0;
    p_sys->p_block_audio = 0;

    ParseMRL( p_demux );
Gildas Bazin's avatar
 
Gildas Bazin committed
420 421 422 423

    /* Find main device (video or audio) */
    if( p_sys->psz_device && *p_sys->psz_device )
    {
424
        msg_Dbg( p_demux, "main device=`%s'", p_sys->psz_device );
Gildas Bazin's avatar
 
Gildas Bazin committed
425 426

        /* Try to open as video device */
427
        p_sys->fd_video = OpenVideoDev( p_demux, p_sys->psz_device );
Gildas Bazin's avatar
 
Gildas Bazin committed
428 429 430 431

        if( p_sys->fd_video < 0 )
        {
            /* Try to open as audio device */
432
            p_sys->fd_audio = OpenAudioDev( p_demux, p_sys->psz_device );
Gildas Bazin's avatar
 
Gildas Bazin committed
433 434
            if( p_sys->fd_audio >= 0 )
            {
435
                free( p_sys->psz_adev );
Gildas Bazin's avatar
 
Gildas Bazin committed
436 437 438 439 440 441
                p_sys->psz_adev = p_sys->psz_device;
                p_sys->psz_device = NULL;
            }
        }
        else
        {
442
            free( p_sys->psz_vdev );
Gildas Bazin's avatar
 
Gildas Bazin committed
443 444 445 446 447 448 449 450
            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 )
    {
451
        if( strcmp( p_demux->psz_access, "v4l" ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
452
        {
453
            Close( p_this );
Gildas Bazin's avatar
 
Gildas Bazin committed
454 455 456 457 458 459 460 461 462
            return VLC_EGENERIC;
        }
    }

    /* Find video device */
    if( p_sys->fd_video < 0 )
    {
        if( !p_sys->psz_vdev || !*p_sys->psz_vdev )
        {
463
            free( p_sys->psz_vdev );
464
            p_sys->psz_vdev = var_CreateGetString( p_demux, "v4l-vdev" );;
Gildas Bazin's avatar
 
Gildas Bazin committed
465 466 467 468
        }

        if( p_sys->psz_vdev && *p_sys->psz_vdev )
        {
469
            p_sys->fd_video = OpenVideoDev( p_demux, p_sys->psz_vdev );
Gildas Bazin's avatar
 
Gildas Bazin committed
470 471 472 473 474 475 476 477
        }
    }

    /* Find audio device */
    if( p_sys->fd_audio < 0 )
    {
        if( !p_sys->psz_adev || !*p_sys->psz_adev )
        {
478
            free( p_sys->psz_adev );
479
            p_sys->psz_adev = var_CreateGetString( p_demux, "v4l-adev" );;
Gildas Bazin's avatar
 
Gildas Bazin committed
480 481 482 483
        }

        if( p_sys->psz_adev && *p_sys->psz_adev )
        {
484
            p_sys->fd_audio = OpenAudioDev( p_demux, p_sys->psz_adev );
Gildas Bazin's avatar
 
Gildas Bazin committed
485 486 487 488 489
        }
    }

    if( p_sys->fd_video < 0 && p_sys->fd_audio < 0 )
    {
490
        Close( p_this );
Gildas Bazin's avatar
 
Gildas Bazin committed
491 492 493
        return VLC_EGENERIC;
    }

494
    msg_Dbg( p_demux, "v4l grabbing started" );
Gildas Bazin's avatar
 
Gildas Bazin committed
495

496
    /* Declare elementary streams */
Gildas Bazin's avatar
 
Gildas Bazin committed
497 498
    if( p_sys->fd_video >= 0 )
    {
499 500 501 502
        es_format_t fmt;
        es_format_Init( &fmt, VIDEO_ES, p_sys->i_fourcc );
        fmt.video.i_width  = p_sys->i_width;
        fmt.video.i_height = p_sys->i_height;
503 504 505 506 507 508 509 510 511 512
        fmt.video.i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;

        /* Setup rgb mask for RGB formats */
        if( p_sys->i_fourcc == VLC_FOURCC('R','V','2','4') )
        {
            /* This is in BGR format */
            fmt.video.i_bmask = 0x00ff0000;
            fmt.video.i_gmask = 0x0000ff00;
            fmt.video.i_rmask = 0x000000ff;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
513

514 515 516
        msg_Dbg( p_demux, "added new video es %4.4s %dx%d",
                 (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height );
        p_sys->p_es_video = es_out_Add( p_demux->out, &fmt );
Gildas Bazin's avatar
 
Gildas Bazin committed
517 518 519 520
    }

    if( p_sys->fd_audio >= 0 )
    {
521 522
        es_format_t fmt;
        es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC('a','r','a','w') );
Gildas Bazin's avatar
 
Gildas Bazin committed
523

524 525 526 527 528 529 530
        fmt.audio.i_channels = p_sys->b_stereo ? 2 : 1;
        fmt.audio.i_rate = p_sys->i_sample_rate;
        fmt.audio.i_bitspersample = 16; // FIXME ?
        fmt.audio.i_blockalign = fmt.audio.i_channels *
            fmt.audio.i_bitspersample / 8;
        fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate *
            fmt.audio.i_bitspersample;
Gildas Bazin's avatar
 
Gildas Bazin committed
531

532 533
        msg_Dbg( p_demux, "new audio es %d channels %dHz",
                 fmt.audio.i_channels, fmt.audio.i_rate );
Gildas Bazin's avatar
 
Gildas Bazin committed
534

535
        p_sys->p_es_audio = es_out_Add( p_demux->out, &fmt );
Gildas Bazin's avatar
 
Gildas Bazin committed
536 537
    }

538
    /* Update default_pts to a suitable value for access */
539
    var_Create( p_demux, "v4l-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
540

Gildas Bazin's avatar
 
Gildas Bazin committed
541 542 543
    return VLC_SUCCESS;
}

544
/*****************************************************************************
545
 * Close: close device, free resources
546
 *****************************************************************************/
547
static void Close( vlc_object_t *p_this )
548
{
549 550
    demux_t     *p_demux = (demux_t *)p_this;
    demux_sys_t *p_sys   = p_demux->p_sys;
551

552 553 554
    free( p_sys->psz_device );
    free( p_sys->psz_vdev );
    free( p_sys->psz_adev );
555 556
    if( p_sys->fd_video >= 0 ) close( p_sys->fd_video );
    if( p_sys->fd_audio >= 0 ) close( p_sys->fd_audio );
557
    if( p_sys->p_block_audio ) block_Release( p_sys->p_block_audio );
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577

    if( p_sys->b_mjpeg )
    {
        int i_noframe = -1;
        ioctl( p_sys->fd_video, MJPIOC_QBUF_CAPT, &i_noframe );
    }

    if( p_sys->p_video_mmap && p_sys->p_video_mmap != MAP_FAILED )
    {
        if( p_sys->b_mjpeg )
            munmap( p_sys->p_video_mmap, p_sys->mjpeg_buffers.size *
                    p_sys->mjpeg_buffers.count );
        else
            munmap( p_sys->p_video_mmap, p_sys->vid_mbuf.size );
    }

    free( p_sys );
}

/*****************************************************************************
578
 * Control:
579
 *****************************************************************************/
580
static int Control( demux_t *p_demux, int i_query, va_list args )
581
{
582
    bool *pb;
583
    int64_t    *pi64;
584 585 586

    switch( i_query )
    {
587 588
        /* Special for access_demux */
        case DEMUX_CAN_PAUSE:
589
        case DEMUX_CAN_SEEK:
590 591
        case DEMUX_SET_PAUSE_STATE:
        case DEMUX_CAN_CONTROL_PACE:
592 593
            pb = (bool*)va_arg( args, bool * );
            *pb = false;
594 595 596 597 598 599 600
            return VLC_SUCCESS;

        case DEMUX_GET_PTS_DELAY:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = (int64_t)var_GetInteger( p_demux, "v4l-caching" ) * 1000;
            return VLC_SUCCESS;

601 602 603 604 605
        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = mdate();
            return VLC_SUCCESS;

606
        /* TODO implement others */
607 608 609
        default:
            return VLC_EGENERIC;
    }
610 611

    return VLC_EGENERIC;
612 613 614
}

/*****************************************************************************
615
 * Demux:
616
 *****************************************************************************/
617
static int Demux( demux_t *p_demux )
618
{
619 620
    demux_sys_t *p_sys = p_demux->p_sys;
    es_out_id_t  *p_es = p_sys->p_es_audio;
621
    block_t *p_block = NULL;
622

623 624
    /* Try grabbing audio frames first */
    if( p_sys->fd_audio < 0 || !( p_block = GrabAudio( p_demux ) ) )
625
    {
626 627 628 629
        /* Try grabbing video frame */
        p_es = p_sys->p_es_video;
        if( p_sys->fd_video > 0 ) p_block = GrabVideo( p_demux );
    }
630

631 632 633 634 635 636
    if( !p_block )
    {
        /* Sleep so we do not consume all the cpu, 10ms seems
         * like a good value (100fps) */
        msleep( 10000 );
        return 1;
637 638
    }

639 640 641 642
    es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
    es_out_Send( p_demux->out, p_es, p_block );

    return 1;
643 644
}

Gildas Bazin's avatar
 
Gildas Bazin committed
645 646 647
/*****************************************************************************
 * ParseMRL: parse the options contained in the MRL
 *****************************************************************************/
648
static void ParseMRL( demux_t *p_demux )
Gildas Bazin's avatar
 
Gildas Bazin committed
649
{
650
    demux_sys_t *p_sys = p_demux->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
651

652
    char *psz_dup = strdup( p_demux->psz_path );
Gildas Bazin's avatar
 
Gildas Bazin committed
653
    char *psz_parser = psz_dup;
654 655 656 657 658 659 660 661 662 663 664 665 666 667

    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }

    if( *psz_parser == ':' )
    {
        /* read options */
        for( ;; )
        {
            *psz_parser++ = '\0';
            if( !strncmp( psz_parser, "channel=", strlen( "channel=" ) ) )
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
668 669
                p_sys->i_channel = strtol( psz_parser + strlen( "channel=" ),
                                           &psz_parser, 0 );
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
            }
            else if( !strncmp( psz_parser, "norm=", strlen( "norm=" ) ) )
            {
                psz_parser += strlen( "norm=" );
                if( !strncmp( psz_parser, "pal", strlen( "pal" ) ) )
                {
                    p_sys->i_norm = VIDEO_MODE_PAL;
                    psz_parser += strlen( "pal" );
                }
                else if( !strncmp( psz_parser, "ntsc", strlen( "ntsc" ) ) )
                {
                    p_sys->i_norm = VIDEO_MODE_NTSC;
                    psz_parser += strlen( "ntsc" );
                }
                else if( !strncmp( psz_parser, "secam", strlen( "secam" ) ) )
                {
                    p_sys->i_norm = VIDEO_MODE_SECAM;
                    psz_parser += strlen( "secam" );
                }
                else if( !strncmp( psz_parser, "auto", strlen( "auto" ) ) )
                {
                    p_sys->i_norm = VIDEO_MODE_AUTO;
                    psz_parser += strlen( "auto" );
                }
                else
                {
                    p_sys->i_norm = strtol( psz_parser, &psz_parser, 0 );
                }
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
699 700
            else if( !strncmp( psz_parser, "frequency=",
                               strlen( "frequency=" ) ) )
701 702
            {
                p_sys->i_frequency =
Gildas Bazin's avatar
 
Gildas Bazin committed
703 704
                    strtol( psz_parser + strlen( "frequency=" ),
                            &psz_parser, 0 );
705 706
                if( p_sys->i_frequency < 30000 )
                {
707
                    msg_Warn( p_demux, "v4l syntax has changed : "
Gildas Bazin's avatar
 
Gildas Bazin committed
708
                              "'frequency' is now channel frequency in kHz");
709
                }
710 711 712
            }
            else if( !strncmp( psz_parser, "audio=", strlen( "audio=" ) ) )
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
713 714
                p_sys->i_audio = strtol( psz_parser + strlen( "audio=" ),
                                         &psz_parser, 0 );
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
            }
            else if( !strncmp( psz_parser, "size=", strlen( "size=" ) ) )
            {
                psz_parser += strlen( "size=" );
                if( !strncmp( psz_parser, "subqcif", strlen( "subqcif" ) ) )
                {
                    p_sys->i_width  = 128;
                    p_sys->i_height = 96;
                }
                else if( !strncmp( psz_parser, "qsif", strlen( "qsif" ) ) )
                {
                    p_sys->i_width  = 160;
                    p_sys->i_height = 120;
                }
                else if( !strncmp( psz_parser, "qcif", strlen( "qcif" ) ) )
                {
                    p_sys->i_width  = 176;
                    p_sys->i_height = 144;
                }
                else if( !strncmp( psz_parser, "sif", strlen( "sif" ) ) )
                {
                    p_sys->i_width  = 320;
                    p_sys->i_height = 244;
                }
                else if( !strncmp( psz_parser, "cif", strlen( "cif" ) ) )
                {
                    p_sys->i_width  = 352;
                    p_sys->i_height = 288;
                }
                else if( !strncmp( psz_parser, "vga", strlen( "vga" ) ) )
                {
                    p_sys->i_width  = 640;
                    p_sys->i_height = 480;
                }
                else
                {
                    /* widthxheight */
                    p_sys->i_width = strtol( psz_parser, &psz_parser, 0 );
                    if( *psz_parser == 'x' || *psz_parser == 'X')
                    {
Gildas Bazin's avatar
 
Gildas Bazin committed
755 756
                        p_sys->i_height = strtol( psz_parser + 1,
                                                  &psz_parser, 0 );
757
                    }
758
                    msg_Dbg( p_demux, "WxH %dx%d", p_sys->i_width,
Gildas Bazin's avatar
 
Gildas Bazin committed
759
                             p_sys->i_height );
760 761
                }
            }
762 763 764 765 766 767 768 769 770 771 772 773
            else if( !strncmp( psz_parser, "brightness=", strlen( "brightness=" ) ) )
            {
                p_sys->i_brightness = strtol( psz_parser + strlen( "brightness=" ),
                                              &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "colour=", strlen( "colour=" ) ) )
            {
                p_sys->i_colour = strtol( psz_parser + strlen( "colour=" ),
                                          &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "hue=", strlen( "hue=" ) ) )
            {
774
                p_sys->i_hue = strtol( psz_parser + strlen( "hue=" ),
775 776 777 778 779 780 781
                                       &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "contrast=", strlen( "contrast=" ) ) )
            {
                p_sys->i_contrast = strtol( psz_parser + strlen( "contrast=" ),
                                            &psz_parser, 0 );
            }
782 783
            else if( !strncmp( psz_parser, "tuner=", strlen( "tuner=" ) ) )
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
784 785
                p_sys->i_tuner = strtol( psz_parser + strlen( "tuner=" ),
                                         &psz_parser, 0 );
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
            }
            else if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) ) )
            {
                int  i_len;

                psz_parser += strlen( "adev=" );
                if( strchr( psz_parser, ':' ) )
                {
                    i_len = strchr( psz_parser, ':' ) - psz_parser;
                }
                else
                {
                    i_len = strlen( psz_parser );
                }

                p_sys->psz_adev = strndup( psz_parser, i_len );

                psz_parser += i_len;
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
805 806
            else if( !strncmp( psz_parser, "samplerate=",
                               strlen( "samplerate=" ) ) )
807
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
808 809 810
                p_sys->i_sample_rate =
                    strtol( psz_parser + strlen( "samplerate=" ),
                            &psz_parser, 0 );
811 812 813 814 815
            }
            else if( !strncmp( psz_parser, "stereo", strlen( "stereo" ) ) )
            {
                psz_parser += strlen( "stereo" );

816
                p_sys->b_stereo = true;
817 818 819 820 821
            }
            else if( !strncmp( psz_parser, "mono", strlen( "mono" ) ) )
            {
                psz_parser += strlen( "mono" );

822
                p_sys->b_stereo = false;
823
            }
824 825 826 827
            else if( !strncmp( psz_parser, "mjpeg", strlen( "mjpeg" ) ) )
            {
                psz_parser += strlen( "mjpeg" );

828
                p_sys->b_mjpeg = true;
829
            }
Sam Hocevar's avatar
Sam Hocevar committed
830
            else if( !strncmp( psz_parser, "decimation=",
831 832
                        strlen( "decimation=" ) ) )
            {
Sam Hocevar's avatar
Sam Hocevar committed
833
                p_sys->i_decimation =
834 835 836 837 838 839 840 841 842 843
                    strtol( psz_parser + strlen( "decimation=" ),
                            &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "quality=",
                        strlen( "quality=" ) ) )
            {
                p_sys->i_quality =
                    strtol( psz_parser + strlen( "quality=" ),
                            &psz_parser, 0 );
            }
844 845 846 847 848
            else if( !strncmp( psz_parser, "fps=", strlen( "fps=" ) ) )
            {
                p_sys->f_fps = strtof( psz_parser + strlen( "fps=" ),
                                       &psz_parser );
            }
849 850
            else
            {
851
                msg_Warn( p_demux, "unknown option" );
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
            }

            while( *psz_parser && *psz_parser != ':' )
            {
                psz_parser++;
            }

            if( *psz_parser == '\0' )
            {
                break;
            }
        }
    }

    if( *psz_dup )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
868
        p_sys->psz_device = strdup( psz_dup );
869
    }
870
    free( psz_dup );
Gildas Bazin's avatar
 
Gildas Bazin committed
871
}
872

Gildas Bazin's avatar
 
Gildas Bazin committed
873 874 875
/*****************************************************************************
 * OpenVideoDev:
 *****************************************************************************/
876
static int OpenVideoDev( demux_t *p_demux, char *psz_device )
Gildas Bazin's avatar
 
Gildas Bazin committed
877
{
878
    demux_sys_t *p_sys = p_demux->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
879
    int i_fd;
880

Gildas Bazin's avatar
 
Gildas Bazin committed
881 882 883
    struct video_channel vid_channel;
    struct mjpeg_params mjpeg;
    int i;
884

Gildas Bazin's avatar
 
Gildas Bazin committed
885
    if( ( i_fd = open( psz_device, O_RDWR ) ) < 0 )
886
    {
887
        msg_Err( p_demux, "cannot open device (%m)" );
Gildas Bazin's avatar
 
Gildas Bazin committed
888
        goto vdev_failed;
889 890
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
891
    if( ioctl( i_fd, VIDIOCGCAP, &p_sys->vid_cap ) < 0 )
892
    {
893
        msg_Err( p_demux, "cannot get capabilities (%m)" );
Gildas Bazin's avatar
 
Gildas Bazin committed
894
        goto vdev_failed;
895 896
    }

897
    msg_Dbg( p_demux,
898 899 900 901 902 903 904 905 906
             "V4L device %s %d channels %d audios %d < w < %d %d < h < %d",
             p_sys->vid_cap.name,
             p_sys->vid_cap.channels,
             p_sys->vid_cap.audios,
             p_sys->vid_cap.minwidth,  p_sys->vid_cap.maxwidth,
             p_sys->vid_cap.minheight, p_sys->vid_cap.maxheight );

    if( p_sys->i_channel < 0 || p_sys->i_channel >= p_sys->vid_cap.channels )
    {
907
        msg_Dbg( p_demux, "invalid channel, falling back on channel 0" );
908 909
        p_sys->i_channel = 0;
    }
910
    if( p_sys->vid_cap.audios && p_sys->i_audio >= p_sys->vid_cap.audios )
911
    {
912
        msg_Dbg( p_demux, "invalid audio, falling back with no audio" );
913 914 915 916 917 918
        p_sys->i_audio = -1;
    }

    if( p_sys->i_width < p_sys->vid_cap.minwidth ||
        p_sys->i_width > p_sys->vid_cap.maxwidth )
    {
919
        msg_Dbg( p_demux, "invalid width %i", p_sys->i_width );
920 921 922 923 924
        p_sys->i_width = 0;
    }
    if( p_sys->i_height < p_sys->vid_cap.minheight ||
        p_sys->i_height > p_sys->vid_cap.maxheight )
    {
925
        msg_Dbg( p_demux, "invalid height %i", p_sys->i_height );
926 927 928
        p_sys->i_height = 0;
    }

Sam Hocevar's avatar
Sam Hocevar committed
929
    if( !( p_sys->vid_cap.type & VID_TYPE_CAPTURE ) )
930
    {
931
        msg_Err( p_demux, "cannot grab" );
Gildas Bazin's avatar
 
Gildas Bazin committed
932
        goto vdev_failed;
933 934 935
    }

    vid_channel.channel = p_sys->i_channel;
Gildas Bazin's avatar
 
Gildas Bazin committed
936
    if( ioctl( i_fd, VIDIOCGCHAN, &vid_channel ) < 0 )
937
    {
938
        msg_Err( p_demux, "cannot get channel infos (%m)" );
Gildas Bazin's avatar
 
Gildas Bazin committed
939
        goto vdev_failed;
940
    }
941
    msg_Dbg( p_demux,
942
             "setting channel %s(%d) %d tuners flags=0x%x type=0x%x norm=0x%x",
943 944
             vid_channel.name, vid_channel.channel, vid_channel.tuners,
             vid_channel.flags, vid_channel.type, vid_channel.norm );
945 946 947

    if( p_sys->i_tuner >= vid_channel.tuners )
    {
948
        msg_Dbg( p_demux, "invalid tuner, falling back on tuner 0" );
949 950 951 952
        p_sys->i_tuner = 0;
    }

    vid_channel.norm = p_sys->i_norm;
Gildas Bazin's avatar
 
Gildas Bazin committed
953
    if( ioctl( i_fd, VIDIOCSCHAN, &vid_channel ) < 0 )
954
    {
955
        msg_Err( p_demux, "cannot set channel (%m)" );
Gildas Bazin's avatar
 
Gildas Bazin committed
956
        goto vdev_failed;
957 958 959 960 961 962 963 964 965 966 967
    }

    if( vid_channel.flags & VIDEO_VC_TUNER )
    {

        /* set tuner */
#if 0
        struct video_tuner vid_tuner;
        if( p_sys->i_tuner >= 0 )
        {
            vid_tuner.tuner = p_sys->i_tuner;
Gildas Bazin's avatar
 
Gildas Bazin committed
968
            if( ioctl( i_fd, VIDIOCGTUNER, &vid_tuner ) < 0 )
969
            {
970
                msg_Err( p_demux, "cannot get tuner (%m)" );
Gildas Bazin's avatar
 
Gildas Bazin committed
971
                goto vdev_failed;
972
            }
973
            msg_Dbg( p_demux, "tuner %s low=%d high=%d, flags=0x%x "
Gildas Bazin's avatar
 
Gildas Bazin committed
974 975 976 977
                     "mode=0x%x signal=0x%x",
                     vid_tuner.name, vid_tuner.rangelow, vid_tuner.rangehigh,
                     vid_tuner.flags, vid_tuner.mode, vid_tuner.signal );

978
            msg_Dbg( p_demux, "setting tuner %s (%d)",
979 980
                     vid_tuner.name, vid_tuner.tuner );

Gildas Bazin's avatar
 
Gildas Bazin committed
981 982 983
            /* FIXME FIXME to be checked FIXME FIXME */
            //vid_tuner.mode = p_sys->i_norm;
            if( ioctl( i_fd, VIDIOCSTUNER, &vid_tuner ) < 0 )
984
            {