v4l2.c 118 KB
Newer Older
1
2
3
/*****************************************************************************
 * v4l2.c : Video4Linux2 input module for vlc
 *****************************************************************************
dionoea's avatar
dionoea committed
4
 * Copyright (C) 2002-2009 the VideoLAN team
5
 * $Id$
6
 *
7
8
 * Authors: Benjamin Pracht <bigben at videolan dot org>
 *          Richard Hosking <richard at hovis dot net>
9
10
 *          Antoine Cellerier <dionoea at videolan d.t org>
 *          Dennis Lou <dlou99 at yahoo dot com>
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
24
25
26
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

27
/*
28
29
30
 * Sections based on the reference V4L2 capture example at
 * http://v4l2spec.bytesex.org/spec/capture-example.html
 */
31

32
33
34
35
/*****************************************************************************
 * Preamble
 *****************************************************************************/

36
37
38
39
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

40
#include <vlc_common.h>
41
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
42
#include <vlc_access.h>
43
#include <vlc_charset.h>
44
#include <vlc_fs.h>
45
#include <vlc_demux.h>
zorglub's avatar
zorglub committed
46
#include <vlc_input.h>
47

48
#include <ctype.h>
49
#include <errno.h>
50
51
#include <fcntl.h>
#include <sys/ioctl.h>
52
#include <sys/mman.h>
53
54
55

#include <linux/videodev2.h>

56
57
#include <poll.h>

58
59
60
61
#ifdef HAVE_LIBV4L2
#   include <libv4l2.h>
#endif

62
63
/*****************************************************************************
 * Module descriptior
64
 *****************************************************************************/
65

66
67
68
69
static int  DemuxOpen ( vlc_object_t * );
static void DemuxClose( vlc_object_t * );
static int  AccessOpen ( vlc_object_t * );
static void AccessClose( vlc_object_t * );
70

71
72
73
74
75
76
#define STANDARD_TEXT N_( "Standard" )
#define STANDARD_LONGTEXT N_( \
    "Video standard (Default, SECAM, PAL, or NTSC)." )
#define CHROMA_TEXT N_("Video input chroma format")
#define CHROMA_LONGTEXT N_( \
    "Force the Video4Linux2 video device to use a specific chroma format " \
dionoea's avatar
dionoea committed
77
    "(eg. I420 or I422 for raw images, MJPG for M-JPEG compressed input) " \
78
79
    "(Complete list: GREY, I240, RV16, RV15, RV24, RV32, YUY2, YUYV, UYVY, " \
    "I41N, I422, I420, I411, I410, MJPG)")
bigben's avatar
bigben committed
80
81
#define INPUT_TEXT N_( "Input" )
#define INPUT_LONGTEXT N_( \
82
83
84
85
    "Input of the card to use (see debug)." )
#define AUDIO_INPUT_TEXT N_( "Audio input" )
#define AUDIO_INPUT_LONGTEXT N_( \
    "Audio input of the card to use (see debug)." )
86
87
88
#define IOMETHOD_TEXT N_( "IO Method" )
#define IOMETHOD_LONGTEXT N_( \
    "IO Method (READ, MMAP, USERPTR)." )
89
90
#define WIDTH_TEXT N_( "Width" )
#define WIDTH_LONGTEXT N_( \
91
    "Force width (-1 for autodetect, 0 for driver default)." )
92
93
#define HEIGHT_TEXT N_( "Height" )
#define HEIGHT_LONGTEXT N_( \
94
    "Force height (-1 for autodetect, 0 for driver default)." )
95
96
#define FPS_TEXT N_( "Framerate" )
#define FPS_LONGTEXT N_( "Framerate to capture, if applicable " \
97
    "(0 for autodetect)." )
98

dionoea's avatar
dionoea committed
99
100
101
102
103
104
#ifdef HAVE_LIBV4L2
#define LIBV4L2_TEXT N_( "Use libv4l2" )
#define LIBV4L2_LONGTEXT N_( \
    "Force usage of the libv4l2 wrapper." )
#endif

105
106
107
#define CTRL_RESET_TEXT N_( "Reset v4l2 controls" )
#define CTRL_RESET_LONGTEXT N_( \
    "Reset controls to defaults provided by the v4l2 driver." )
108
109
#define BRIGHTNESS_TEXT N_( "Brightness" )
#define BRIGHTNESS_LONGTEXT N_( \
110
    "Brightness of the video input (if supported by the v4l2 driver)." )
111
112
#define CONTRAST_TEXT N_( "Contrast" )
#define CONTRAST_LONGTEXT N_( \
113
    "Contrast of the video input (if supported by the v4l2 driver)." )
114
115
#define SATURATION_TEXT N_( "Saturation" )
#define SATURATION_LONGTEXT N_( \
116
    "Saturation of the video input (if supported by the v4l2 driver)." )
117
118
#define HUE_TEXT N_( "Hue" )
#define HUE_LONGTEXT N_( \
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
    "Hue of the video input (if supported by the v4l2 driver)." )
#define BLACKLEVEL_TEXT N_( "Black level" )
#define BLACKLEVEL_LONGTEXT N_( \
    "Black level of the video input (if supported by the v4l2 driver)." )
#define AUTOWHITEBALANCE_TEXT N_( "Auto white balance" )
#define AUTOWHITEBALANCE_LONGTEXT N_( \
    "Automatically set the white balance of the video input " \
    "(if supported by the v4l2 driver)." )
#define DOWHITEBALANCE_TEXT N_( "Do white balance" )
#define DOWHITEBALANCE_LONGTEXT N_( \
    "Trigger a white balancing action, useless if auto white balance is " \
    "activated (if supported by the v4l2 driver)." )
#define REDBALANCE_TEXT N_( "Red balance" )
#define REDBALANCE_LONGTEXT N_( \
    "Red balance of the video input (if supported by the v4l2 driver)." )
#define BLUEBALANCE_TEXT N_( "Blue balance" )
#define BLUEBALANCE_LONGTEXT N_( \
    "Blue balance of the video input (if supported by the v4l2 driver)." )
137
138
#define GAMMA_TEXT N_( "Gamma" )
#define GAMMA_LONGTEXT N_( \
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    "Gamma of the video input (if supported by the v4l2 driver)." )
#define EXPOSURE_TEXT N_( "Exposure" )
#define EXPOSURE_LONGTEXT N_( \
    "Exposure of the video input (if supported by the v4L2 driver)." )
#define AUTOGAIN_TEXT N_( "Auto gain" )
#define AUTOGAIN_LONGTEXT N_( \
    "Automatically set the video input's gain (if supported by the " \
    "v4l2 driver)." )
#define GAIN_TEXT N_( "Gain" )
#define GAIN_LONGTEXT N_( \
    "Video input's gain (if supported by the v4l2 driver)." )
#define HFLIP_TEXT N_( "Horizontal flip" )
#define HFLIP_LONGTEXT N_( \
    "Flip the video horizontally (if supported by the v4l2 driver)." )
#define VFLIP_TEXT N_( "Vertical flip" )
#define VFLIP_LONGTEXT N_( \
    "Flip the video vertically (if supported by the v4l2 driver)." )
#define HCENTER_TEXT N_( "Horizontal centering" )
#define HCENTER_LONGTEXT N_( \
    "Set the camera's horizontal centering (if supported by the v4l2 driver)." )
#define VCENTER_TEXT N_( "Vertical centering" )
#define VCENTER_LONGTEXT N_( \
    "Set the camera's vertical centering (if supported by the v4l2 driver)." )
162

163
164
#define AUDIO_VOLUME_TEXT N_( "Volume" )
#define AUDIO_VOLUME_LONGTEXT N_( \
165
    "Volume of the audio input (if supported by the v4l2 driver)." )
166
167
#define AUDIO_BALANCE_TEXT N_( "Balance" )
#define AUDIO_BALANCE_LONGTEXT N_( \
168
    "Balance of the audio input (if supported by the v4l2 driver)." )
169
170
#define AUDIO_MUTE_TEXT N_( "Mute" )
#define AUDIO_MUTE_LONGTEXT N_( \
171
172
173
174
175
176
177
178
179
180
181
    "Mute audio input (if supported by the v4l2 driver)." )
#define AUDIO_BASS_TEXT N_( "Bass" )
#define AUDIO_BASS_LONGTEXT N_( \
    "Bass level of the audio input (if supported by the v4l2 driver)." )
#define AUDIO_TREBLE_TEXT N_( "Treble" )
#define AUDIO_TREBLE_LONGTEXT N_( \
    "Treble level of the audio input (if supported by the v4l2 driver)." )
#define AUDIO_LOUDNESS_TEXT N_( "Loudness" )
#define AUDIO_LOUDNESS_LONGTEXT N_( \
    "Loudness of the audio input (if supported by the v4l2 driver)." )

182
183
184
185
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
    "Caching value for V4L2 captures. This " \
    "value should be set in milliseconds." )
186
187
188
189
190
191
192
#define S_CTRLS_TEXT N_("v4l2 driver controls")
#define S_CTRLS_LONGTEXT N_( \
    "Set the v4l2 driver controls to the values specified using a comma " \
    "separated list optionally encapsulated by curly braces " \
    "(e.g.: {video_bitrate=6000000,audio_crc=0,stream_type=3} ). " \
    "To list available controls, increase verbosity (-vvv) " \
    "or use the v4l2-ctl application." )
193

194
195
196
197
198
199
200
201
202
203
#define TUNER_TEXT N_("Tuner id")
#define TUNER_LONGTEXT N_( \
    "Tuner id (see debug output)." )
#define FREQUENCY_TEXT N_("Frequency")
#define FREQUENCY_LONGTEXT N_( \
    "Tuner frequency in Hz or kHz (see debug output)" )
#define TUNER_AUDIO_MODE_TEXT N_("Audio mode")
#define TUNER_AUDIO_MODE_LONGTEXT N_( \
    "Tuner audio mono/stereo and track selection." )

204
205
#define AUDIO_DEPRECATED_ERROR N_( \
    "Alsa or OSS audio capture in the v4l2 access is deprecated. " \
206
207
    "please use 'v4l2:/""/ :input-slave=alsa:/""/' or " \
    "'v4l2:/""/ :input-slave=oss:/""/' instead." )
208

209
210
211
#define ASPECT_TEXT N_("Picture aspect-ratio n:m")
#define ASPECT_LONGTEXT N_("Define input picture aspect-ratio to use. Default is 4:3" )

212
typedef enum {
dionoea's avatar
dionoea committed
213
    IO_METHOD_AUTO,
214
215
216
217
218
    IO_METHOD_READ,
    IO_METHOD_MMAP,
    IO_METHOD_USERPTR,
} io_method;

219
static const int i_standards_list[] =
dionoea's avatar
dionoea committed
220
221
222
223
224
225
226
227
228
229
230
    { V4L2_STD_UNKNOWN, V4L2_STD_SECAM, V4L2_STD_PAL, V4L2_STD_NTSC,
      V4L2_STD_PAL_B, V4L2_STD_PAL_B1, V4L2_STD_PAL_G, V4L2_STD_PAL_H,
      V4L2_STD_PAL_I, V4L2_STD_PAL_D, V4L2_STD_PAL_D1, V4L2_STD_PAL_K,
      V4L2_STD_PAL_M, V4L2_STD_PAL_N, V4L2_STD_PAL_Nc, V4L2_STD_PAL_60,
      V4L2_STD_NTSC_M, V4L2_STD_NTSC_M_JP, V4L2_STD_NTSC_443,
      V4L2_STD_NTSC_M_KR,
      V4L2_STD_SECAM_B, V4L2_STD_SECAM_D, V4L2_STD_SECAM_G,
      V4L2_STD_SECAM_H, V4L2_STD_SECAM_K, V4L2_STD_SECAM_K1,
      V4L2_STD_SECAM_L, V4L2_STD_SECAM_LC,
      V4L2_STD_ATSC_8_VSB, V4L2_STD_ATSC_16_VSB,
      };
231
static const char *const psz_standards_list_text[] =
dionoea's avatar
dionoea committed
232
233
234
235
236
237
238
239
    { N_("Default"), "SECAM", "PAL",  "NTSC",
      "PAL_B", "PAL_B1", "PAL_G", "PAL_H", "PAL_I", "PAL_D",
      "PAL_D1", "PAL_K", "PAL_M", "PAL_N", "PAL_Nc", "PAL_60",
      "NTSC_M", "NTSC_M_JP", "NTSC_443", "NTSC_M_KR",
      "SECAM_B", "SECAM_D", "SECAM_G", "SECAM_H", "SECAM_K",
      "SECAM_K1", "SECAM_L", "SECAM_LC",
      "ATSC_8_VSB", "ATSC_16_VSB"
    };
240

241
static const int i_iomethod_list[] =
dionoea's avatar
dionoea committed
242
    { IO_METHOD_AUTO, IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR };
243
static const char *const psz_iomethod_list_text[] =
dionoea's avatar
dionoea committed
244
    { N_("AUTO"), N_("READ"), N_("MMAP"),  N_("USERPTR") };
245

246
static const int i_tuner_audio_modes_list[] =
247
248
249
    { V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO,
      V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2,
      V4L2_TUNER_MODE_SAP, V4L2_TUNER_MODE_LANG1_LANG2 };
250
static const char *const psz_tuner_audio_modes_list_text[] =
251
252
253
254
255
256
257
    { N_( "Mono" ),
      N_( "Stereo" ),
      N_( "Primary language (Analog TV tuners only)" ),
      N_( "Secondary language (Analog TV tuners only)" ),
      N_( "Second audio program (Analog TV tuners only)" ),
      N_( "Primary language left, Secondary language right" ) };

258
#define V4L2_DEFAULT "/dev/video0"
259
260
#define CFG_PREFIX "v4l2-"

261
262
263
264
265
266
267
268
269
270
#ifdef HAVE_MAEMO
# define DEFAULT_WIDTH	640
# define DEFAULT_HEIGHT	492
#endif

#ifndef DEFAULT_WIDTH
# define DEFAULT_WIDTH	(-1)
# define DEFAULT_HEIGHT	(-1)
#endif

271
272
273
274
275
vlc_module_begin ()
    set_shortname( N_("Video4Linux2") )
    set_description( N_("Video4Linux2 input") )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACCESS )
276

277
    set_section( N_( "Video input" ), NULL )
278
    add_integer( CFG_PREFIX "standard", 0, NULL, STANDARD_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
279
280
                 STANDARD_LONGTEXT, false )
        change_integer_list( i_standards_list, psz_standards_list_text, NULL )
281
    add_string( CFG_PREFIX "chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
282
                true )
283
    add_integer( CFG_PREFIX "input", 0, NULL, INPUT_TEXT, INPUT_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
284
                true )
285
    add_integer( CFG_PREFIX "audio-input", 0, NULL, AUDIO_INPUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
286
                 AUDIO_INPUT_LONGTEXT, true )
dionoea's avatar
dionoea committed
287
    add_integer( CFG_PREFIX "io", IO_METHOD_AUTO, NULL, IOMETHOD_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
288
289
                 IOMETHOD_LONGTEXT, true )
        change_integer_list( i_iomethod_list, psz_iomethod_list_text, NULL )
290
    add_integer( CFG_PREFIX "width", DEFAULT_WIDTH, NULL, WIDTH_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
291
                WIDTH_LONGTEXT, true )
292
    add_integer( CFG_PREFIX "height", DEFAULT_HEIGHT, NULL, HEIGHT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
293
                HEIGHT_LONGTEXT, true )
294
295
    add_string( CFG_PREFIX "aspect-ratio", "4:3", NULL, ASPECT_TEXT,
              ASPECT_LONGTEXT, true )
296
    add_float( CFG_PREFIX "fps", 0, NULL, FPS_TEXT, FPS_LONGTEXT, true )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
297
    add_integer( CFG_PREFIX "caching", 50 /* ms */, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
298
                CACHING_TEXT, CACHING_LONGTEXT, true )
dionoea's avatar
dionoea committed
299
300
301
#ifdef HAVE_LIBV4L2
    add_bool( CFG_PREFIX "use-libv4l2", false, NULL, LIBV4L2_TEXT, LIBV4L2_LONGTEXT, true );
#endif
302

303
    set_section( N_( "Tuner" ), NULL )
304
    add_integer( CFG_PREFIX "tuner", 0, NULL, TUNER_TEXT, TUNER_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
305
                 true )
306
    add_integer( CFG_PREFIX "tuner-frequency", -1, NULL, FREQUENCY_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
307
                 FREQUENCY_LONGTEXT, true )
308
    add_integer( CFG_PREFIX "tuner-audio-mode", -1, NULL, TUNER_AUDIO_MODE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
309
                 TUNER_AUDIO_MODE_LONGTEXT, true )
310
        change_integer_list( i_tuner_audio_modes_list,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
311
                             psz_tuner_audio_modes_list_text, 0 )
312

313
    set_section( N_( "Controls" ),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
314
                 N_( "v4l2 driver controls, if supported by your v4l2 driver." ) )
315
    add_bool( CFG_PREFIX "controls-reset", false, NULL, CTRL_RESET_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
316
              CTRL_RESET_LONGTEXT, true )
317
    add_integer( CFG_PREFIX "brightness", -1, NULL, BRIGHTNESS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
318
                 BRIGHTNESS_LONGTEXT, true )
319
    add_integer( CFG_PREFIX "contrast", -1, NULL, CONTRAST_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
320
                 CONTRAST_LONGTEXT, true )
321
    add_integer( CFG_PREFIX "saturation", -1, NULL, SATURATION_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
322
                 SATURATION_LONGTEXT, true )
323
    add_integer( CFG_PREFIX "hue", -1, NULL, HUE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
324
                 HUE_LONGTEXT, true )
325
    add_integer( CFG_PREFIX "black-level", -1, NULL, BLACKLEVEL_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
326
                 BLACKLEVEL_LONGTEXT, true )
327
    add_integer( CFG_PREFIX "auto-white-balance", -1, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
328
                 AUTOWHITEBALANCE_TEXT, AUTOWHITEBALANCE_LONGTEXT, true )
329
    add_integer( CFG_PREFIX "do-white-balance", -1, NULL, DOWHITEBALANCE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
330
                 DOWHITEBALANCE_LONGTEXT, true )
331
    add_integer( CFG_PREFIX "red-balance", -1, NULL, REDBALANCE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
332
                 REDBALANCE_LONGTEXT, true )
333
    add_integer( CFG_PREFIX "blue-balance", -1, NULL, BLUEBALANCE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
334
                 BLUEBALANCE_LONGTEXT, true )
335
    add_integer( CFG_PREFIX "gamma", -1, NULL, GAMMA_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
336
                 GAMMA_LONGTEXT, true )
337
    add_integer( CFG_PREFIX "exposure", -1, NULL, EXPOSURE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
338
                 EXPOSURE_LONGTEXT, true )
339
    add_integer( CFG_PREFIX "autogain", -1, NULL, AUTOGAIN_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
340
                 AUTOGAIN_LONGTEXT, true )
341
    add_integer( CFG_PREFIX "gain", -1, NULL, GAIN_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
342
                 GAIN_LONGTEXT, true )
343
    add_integer( CFG_PREFIX "hflip", -1, NULL, HFLIP_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
344
                 HFLIP_LONGTEXT, true )
345
    add_integer( CFG_PREFIX "vflip", -1, NULL, VFLIP_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
346
                 VFLIP_LONGTEXT, true )
347
    add_integer( CFG_PREFIX "hcenter", -1, NULL, HCENTER_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
348
                 HCENTER_LONGTEXT, true )
349
    add_integer( CFG_PREFIX "vcenter", -1, NULL, VCENTER_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
350
                 VCENTER_LONGTEXT, true )
351
    add_integer( CFG_PREFIX "audio-volume", -1, NULL, AUDIO_VOLUME_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
352
                AUDIO_VOLUME_LONGTEXT, true )
353
    add_integer( CFG_PREFIX "audio-balance", -1, NULL, AUDIO_BALANCE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
354
                AUDIO_BALANCE_LONGTEXT, true )
355
    add_bool( CFG_PREFIX "audio-mute", false, NULL, AUDIO_MUTE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
356
              AUDIO_MUTE_LONGTEXT, true )
357
    add_integer( CFG_PREFIX "audio-bass", -1, NULL, AUDIO_BASS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
358
                AUDIO_BASS_LONGTEXT, true )
359
    add_integer( CFG_PREFIX "audio-treble", -1, NULL, AUDIO_TREBLE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
360
                AUDIO_TREBLE_LONGTEXT, true )
361
    add_integer( CFG_PREFIX "audio-loudness", -1, NULL, AUDIO_LOUDNESS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
362
                AUDIO_LOUDNESS_LONGTEXT, true )
363
    add_string( CFG_PREFIX "set-ctrls", NULL, NULL, S_CTRLS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
364
              S_CTRLS_LONGTEXT, true )
365

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
366
    add_obsolete_string( CFG_PREFIX "dev" )
367

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
368
369
370
371
    add_obsolete_string( CFG_PREFIX "adev" )
    add_obsolete_integer( CFG_PREFIX "audio-method" )
    add_obsolete_bool( CFG_PREFIX "stereo" )
    add_obsolete_integer( CFG_PREFIX "samplerate" )
372

373
374
375
    add_shortcut( "v4l2" )
    set_capability( "access_demux", 10 )
    set_callbacks( DemuxOpen, DemuxClose )
376

377
    add_submodule ()
378
    add_shortcut( "v4l2" )
379
380
381
    add_shortcut( "v4l2c" )
    set_description( N_("Video4Linux2 Compressed A/V") )
    set_capability( "access", 0 )
382
    /* use these when open as access_demux fails; VLC will use another demux */
383
    set_callbacks( AccessOpen, AccessClose )
384

385
vlc_module_end ()
386
387
388
389
390

/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/

391
392
static void CommonClose( vlc_object_t *, demux_sys_t * );
static void ParseMRL( demux_sys_t *, char *, vlc_object_t * );
393
static void GetV4L2Params( demux_sys_t *, vlc_object_t * );
394
static void SetAvailControlsByString( vlc_object_t *, demux_sys_t *, int );
395

396
static int DemuxControl( demux_t *, int, va_list );
397
static int AccessControl( access_t *, int, va_list );
398

399
static int Demux( demux_t * );
400
static block_t *AccessRead( access_t * );
dionoea's avatar
dionoea committed
401
static ssize_t AccessReadStream( access_t * p_access, uint8_t * p_buffer, size_t i_len );
402

403
404
static block_t* GrabVideo( vlc_object_t *p_demux, demux_sys_t *p_sys );
static block_t* ProcessVideoFrame( vlc_object_t *p_demux, uint8_t *p_frame, size_t );
bigben's avatar
bigben committed
405

406
static bool IsPixelFormatSupported( demux_t *p_demux,
407
                                          unsigned int i_pixelformat );
408

409
410
static int OpenVideoDev( vlc_object_t *, demux_sys_t *, bool );
static bool ProbeVideoDev( vlc_object_t *, demux_sys_t *,
411
                                 const char *psz_device );
412

dionoea's avatar
dionoea committed
413
414
static int ControlList( vlc_object_t *, demux_sys_t *, int , bool, bool );
static int Control( vlc_object_t *, demux_sys_t *, int i_fd,
415
                    const char *psz_name, int i_cid, int i_value );
416
417
418
419
420
421
422
423
424
425

static int DemuxControlCallback( vlc_object_t *p_this, const char *psz_var,
                                 vlc_value_t oldval, vlc_value_t newval,
                                 void *p_data );
static int DemuxControlResetCallback( vlc_object_t *p_this, const char *psz_var,
                                      vlc_value_t oldval, vlc_value_t newval,
                                      void *p_data );
static int AccessControlCallback( vlc_object_t *p_this, const char *psz_var,
                                  vlc_value_t oldval, vlc_value_t newval,
                                  void *p_data );
426
static int AccessControlResetCallback( vlc_object_t *p_this,
427
428
                                       const char *psz_var, vlc_value_t oldval,
                                       vlc_value_t newval, void *p_data );
429

430
static const struct
431
{
432
    unsigned int i_v4l2;
433
    vlc_fourcc_t i_fourcc;
dionoea's avatar
dionoea committed
434
435
436
    int i_rmask;
    int i_gmask;
    int i_bmask;
437
438
} v4l2chroma_to_fourcc[] =
{
439
    /* Raw data types */
440
    { V4L2_PIX_FMT_GREY,    VLC_CODEC_GREY, 0, 0, 0 },
dionoea's avatar
dionoea committed
441
    { V4L2_PIX_FMT_HI240,   VLC_FOURCC('I','2','4','0'), 0, 0, 0 },
442
443
    { V4L2_PIX_FMT_RGB555,  VLC_CODEC_RGB15, 0x001f,0x03e0,0x7c00 },
    { V4L2_PIX_FMT_RGB565,  VLC_CODEC_RGB16, 0x001f,0x07e0,0xf800 },
dionoea's avatar
dionoea committed
444
445
    /* Won't work since we don't know how to handle such gmask values
     * correctly
446
447
    { V4L2_PIX_FMT_RGB555X, VLC_CODEC_RGB15, 0x007c,0xe003,0x1f00 },
    { V4L2_PIX_FMT_RGB565X, VLC_CODEC_RGB16, 0x00f8,0xe007,0x1f00 },
dionoea's avatar
dionoea committed
448
    */
449
450
451
452
453
454
    { V4L2_PIX_FMT_BGR24,   VLC_CODEC_RGB24, 0xff0000,0xff00,0xff },
    { V4L2_PIX_FMT_RGB24,   VLC_CODEC_RGB24, 0xff,0xff00,0xff0000 },
    { V4L2_PIX_FMT_BGR32,   VLC_CODEC_RGB32, 0xff0000,0xff00,0xff },
    { V4L2_PIX_FMT_RGB32,   VLC_CODEC_RGB32, 0xff,0xff00,0xff0000 },
    { V4L2_PIX_FMT_YUYV,    VLC_CODEC_YUYV, 0, 0, 0 },
    { V4L2_PIX_FMT_UYVY,    VLC_CODEC_UYVY, 0, 0, 0 },
dionoea's avatar
dionoea committed
455
    { V4L2_PIX_FMT_Y41P,    VLC_FOURCC('I','4','1','N'), 0, 0, 0 },
456
457
458
459
    { V4L2_PIX_FMT_YUV422P, VLC_CODEC_I422, 0, 0, 0 },
    { V4L2_PIX_FMT_YVU420,  VLC_CODEC_YV12, 0, 0, 0 },
    { V4L2_PIX_FMT_YUV411P, VLC_CODEC_I411, 0, 0, 0 },
    { V4L2_PIX_FMT_YUV410,  VLC_CODEC_I410, 0, 0, 0 },
460
461
462

    /* Raw data types, not in V4L2 spec but still in videodev2.h and supported
     * by VLC */
463
464
    { V4L2_PIX_FMT_YUV420,  VLC_CODEC_I420, 0, 0, 0 },
    /* FIXME { V4L2_PIX_FMT_RGB444,  VLC_CODEC_RGB32 }, */
465

466
    /* Compressed data types */
467
    { V4L2_PIX_FMT_MJPEG,   VLC_CODEC_MJPG, 0, 0, 0 },
dionoea's avatar
dionoea committed
468
    { V4L2_PIX_FMT_JPEG,    VLC_CODEC_JPEG, 0, 0, 0 },
469
470
471
472
#if 0
    { V4L2_PIX_FMT_DV,      VLC_FOURCC('?','?','?','?') },
    { V4L2_PIX_FMT_MPEG,    VLC_FOURCC('?','?','?','?') },
#endif
dionoea's avatar
dionoea committed
473
    { 0, 0, 0, 0, 0 }
474
};
475

476
477
478
/**
 * List of V4L2 chromas were confident enough to use as fallbacks if the
 * user hasn't provided a --v4l2-chroma value.
dionoea's avatar
dionoea committed
479
480
 *
 * Try YUV chromas first, then RGB little endian and MJPEG as last resort.
481
 */
482
static const uint32_t p_chroma_fallbacks[] =
483
{ V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV422P,
dionoea's avatar
dionoea committed
484
  V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_BGR24,
dionoea's avatar
dionoea committed
485
  V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG };
486

487
static const struct
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
{
    const char *psz_name;
    unsigned int i_cid;
} controls[] =
{
    { "brightness", V4L2_CID_BRIGHTNESS },
    { "contrast", V4L2_CID_CONTRAST },
    { "saturation", V4L2_CID_SATURATION },
    { "hue", V4L2_CID_HUE },
    { "audio-volume", V4L2_CID_AUDIO_VOLUME },
    { "audio-balance", V4L2_CID_AUDIO_BALANCE },
    { "audio-bass", V4L2_CID_AUDIO_BASS },
    { "audio-treble", V4L2_CID_AUDIO_TREBLE },
    { "audio-mute", V4L2_CID_AUDIO_MUTE },
    { "audio-loudness", V4L2_CID_AUDIO_LOUDNESS },
    { "black-level", V4L2_CID_BLACK_LEVEL },
    { "auto-white-balance", V4L2_CID_AUTO_WHITE_BALANCE },
    { "do-white-balance", V4L2_CID_DO_WHITE_BALANCE },
    { "red-balance", V4L2_CID_RED_BALANCE },
    { "blue-balance", V4L2_CID_BLUE_BALANCE },
    { "gamma", V4L2_CID_GAMMA },
    { "exposure", V4L2_CID_EXPOSURE },
    { "autogain", V4L2_CID_AUTOGAIN },
    { "gain", V4L2_CID_GAIN },
    { "hflip", V4L2_CID_HFLIP },
    { "vflip", V4L2_CID_VFLIP },
    { "hcenter", V4L2_CID_HCENTER },
    { "vcenter", V4L2_CID_VCENTER },
    { NULL, 0 }
};

519
struct buffer_t
520
521
522
523
524
525
526
{
    void *  start;
    size_t  length;
};

struct demux_sys_t
{
527
528
    char *psz_device;  /* Main device from MRL */
    int  i_fd;
529

530
    char *psz_requested_chroma;
531

532
533
    /* Video */
    io_method io;
534

dionoea's avatar
dionoea committed
535
    int i_cache;
536
537
538
539
540

    struct v4l2_capability dev_cap;

    int i_input;
    struct v4l2_input *p_inputs;
bigben's avatar
bigben committed
541
    int i_selected_input;
542

543
544
545
    int i_standard;
    struct v4l2_standard *p_standards;
    v4l2_std_id i_selected_standard_id;
546
547
548
549

    int i_audio;
    /* V4L2 devices cannot have more than 32 audio inputs */
    struct v4l2_audio p_audios[32];
550
    int i_selected_audio_input;
551
552
553

    int i_tuner;
    struct v4l2_tuner *p_tuners;
bigben's avatar
bigben committed
554
555
556

    int i_codec;
    struct v4l2_fmtdesc *p_codecs;
557

558
559
    struct buffer_t *p_buffers;
    unsigned int i_nbuffers;
560

561
562
    int i_width;
    int i_height;
563
    unsigned int i_aspect;
564
565
566
    float f_fps;            /* <= 0.0 mean to grab at full rate */
    mtime_t i_video_pts;    /* only used when f_fps > 0 */
    int i_fourcc;
567
    uint32_t i_block_flags;
568

569
    es_out_id_t *p_es;
570

571
572
573
574
575
576
    /* Tuner */
    int i_cur_tuner;
    int i_frequency;
    int i_audio_mode;

    /* Controls */
577
    char *psz_set_ctrls;
dionoea's avatar
dionoea committed
578
579
580
581


#ifdef HAVE_LIBV4L2
    /* */
582
    int (*pf_open)(const char *, int, ...);
dionoea's avatar
dionoea committed
583
584
585
586
587
588
    int (*pf_close)( int );
    int (*pf_dup)( int );
    int (*pf_ioctl)( int, unsigned long int, ... );
    ssize_t (*pf_read)( int, void *, size_t );
    void *(*pf_mmap)( void *, size_t, int, int, int, off_t );
    int (*pf_munmap)( void *, size_t );
dionoea's avatar
dionoea committed
589
    bool b_libv4l2;
dionoea's avatar
dionoea committed
590
#endif
591
592
};

dionoea's avatar
dionoea committed
593
594
595
#ifdef HAVE_LIBV4L2
static void use_kernel_v4l2( demux_sys_t *p_sys )
{
596
    p_sys->pf_open = utf8_open;
dionoea's avatar
dionoea committed
597
598
599
600
601
602
    p_sys->pf_close = close;
    p_sys->pf_dup = dup;
    p_sys->pf_ioctl = ioctl;
    p_sys->pf_read = read;
    p_sys->pf_mmap = mmap;
    p_sys->pf_munmap = munmap;
dionoea's avatar
dionoea committed
603
    p_sys->b_libv4l2 = false;
dionoea's avatar
dionoea committed
604
605
606
607
}

static void use_libv4l2( demux_sys_t *p_sys )
{
608
    p_sys->pf_open = v4l2_open;
dionoea's avatar
dionoea committed
609
610
611
612
613
614
    p_sys->pf_close = v4l2_close;
    p_sys->pf_dup = v4l2_dup;
    p_sys->pf_ioctl = v4l2_ioctl;
    p_sys->pf_read = v4l2_read;
    p_sys->pf_mmap = v4l2_mmap;
    p_sys->pf_munmap = v4l2_munmap;
dionoea's avatar
dionoea committed
615
    p_sys->b_libv4l2 = true;
dionoea's avatar
dionoea committed
616
617
}

618
#   define v4l2_open (p_sys->pf_open)
dionoea's avatar
dionoea committed
619
620
621
622
623
624
625
#   define v4l2_close (p_sys->pf_close)
#   define v4l2_dup (p_sys->pf_dup)
#   define v4l2_ioctl (p_sys->pf_ioctl)
#   define v4l2_read (p_sys->pf_read)
#   define v4l2_mmap (p_sys->pf_mmap)
#   define v4l2_munmap (p_sys->pf_munmap)
#else
626
#   define v4l2_open utf8_open
dionoea's avatar
dionoea committed
627
628
629
630
631
632
633
634
#   define v4l2_close close
#   define v4l2_dup dup
#   define v4l2_ioctl ioctl
#   define v4l2_read read
#   define v4l2_mmap mmap
#   define v4l2_munmap munmap
#endif

635
static int FindMainDevice( vlc_object_t *p_this, demux_sys_t *p_sys,
636
                           bool b_demux )
637
{
638
639
640
641
    /* TODO: if using default device, loop through all /dev/video* until
     * one works */
    msg_Dbg( p_this, "opening device '%s'", p_sys->psz_device );
    if( ProbeVideoDev( p_this, p_sys, p_sys->psz_device ) )
642
    {
643
644
        msg_Dbg( p_this, "'%s' is a video device", p_sys->psz_device );
        p_sys->i_fd = OpenVideoDev( p_this, p_sys, b_demux );
645
646
    }

647
    if( p_sys->i_fd < 0 ) return VLC_EGENERIC;
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    return VLC_SUCCESS;
}

/*****************************************************************************
 * DemuxOpen: opens v4l2 device, access_demux callback
 *****************************************************************************
 *
 * url: <video device>::::
 *
 *****************************************************************************/
static int DemuxOpen( vlc_object_t *p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;

    /* Only when selected */
664
665
    if( strcmp( p_demux->psz_access, "v4l2" ) )
        return VLC_EGENERIC;
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680

    /* Set up p_demux */
    p_demux->pf_control = DemuxControl;
    p_demux->pf_demux = Demux;
    p_demux->info.i_update = 0;
    p_demux->info.i_title = 0;
    p_demux->info.i_seekpoint = 0;

    p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
    if( p_sys == NULL ) return VLC_ENOMEM;

    GetV4L2Params(p_sys, (vlc_object_t *) p_demux);

    ParseMRL( p_sys, p_demux->psz_path, (vlc_object_t *) p_demux );

dionoea's avatar
dionoea committed
681
#ifdef HAVE_LIBV4L2
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
682
    if( !var_InheritInteger( p_this, CFG_PREFIX "use-libv4l2" ) )
683
    {
dionoea's avatar
dionoea committed
684
685
686
687
        msg_Dbg( p_this, "Trying direct kernel v4l2" );
        use_kernel_v4l2( p_sys );
        if( FindMainDevice( p_this, p_sys, true ) == VLC_SUCCESS)
            return VLC_SUCCESS;
688
    }
689

dionoea's avatar
dionoea committed
690
691
692
693
694
695
696
697
    msg_Dbg( p_this, "Trying libv4l2 wrapper" );
    use_libv4l2( p_sys );
#endif
    if( FindMainDevice( p_this, p_sys, true ) == VLC_SUCCESS)
        return VLC_SUCCESS;

    DemuxClose( p_this );
    return VLC_EGENERIC;
698
699
}

700
/*****************************************************************************
701
 * GetV4L2Params: fill in p_sys parameters (shared by DemuxOpen and AccessOpen)
702
 *****************************************************************************/
703
static void GetV4L2Params( demux_sys_t *p_sys, vlc_object_t *p_obj )
704
{
705
706
    p_sys->i_video_pts = -1;

707
708
    p_sys->i_selected_standard_id =
        i_standards_list[var_CreateGetInteger( p_obj, "v4l2-standard" )];
709
710

    p_sys->i_selected_input = var_CreateGetInteger( p_obj, "v4l2-input" );
711
712
    p_sys->i_selected_audio_input =
        var_CreateGetInteger( p_obj, "v4l2-audio-input" );
713
714
715
716
717
718

    p_sys->io = var_CreateGetInteger( p_obj, "v4l2-io" );

    p_sys->i_width = var_CreateGetInteger( p_obj, "v4l2-width" );
    p_sys->i_height = var_CreateGetInteger( p_obj, "v4l2-height" );

719
    var_Create( p_obj, "v4l2-controls-reset", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
720

721
    p_sys->f_fps = var_CreateGetFloat( p_obj, "v4l2-fps" );
722
723
    p_sys->psz_requested_chroma = var_CreateGetString( p_obj, "v4l2-chroma" );

dionoea's avatar
dionoea committed
724
    p_sys->i_cache = var_CreateGetInteger( p_obj, "v4l2-caching" );
725

726
727
728
729
    p_sys->i_cur_tuner = var_CreateGetInteger( p_obj, "v4l2-tuner" );
    p_sys->i_frequency = var_CreateGetInteger( p_obj, "v4l2-tuner-frequency" );
    p_sys->i_audio_mode = var_CreateGetInteger( p_obj, "v4l2-tuner-audio-mode" );

730
731
    p_sys->psz_set_ctrls = var_CreateGetString( p_obj, "v4l2-set-ctrls" );

732
    char *psz_aspect = var_CreateGetString( p_obj, "v4l2-aspect-ratio" );
ivoire's avatar
ivoire committed
733
734
    char *psz_delim = !EMPTY_STR(psz_aspect) ? strchr( psz_aspect, ':' ) : NULL;
    if( psz_delim )
735
736
737
738
739
740
741
742
743
744
    {
        p_sys->i_aspect = atoi( psz_aspect ) * VOUT_ASPECT_FACTOR / atoi( psz_delim + 1 );
    }
    else
    {
        p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3 ;

    }
    free( psz_aspect );

745
746
    p_sys->psz_device = NULL;
    p_sys->i_fd = -1;
747

748
    p_sys->p_es = NULL;
749
750
751
752
753
754
755
756
}

/*****************************************************************************
 * ParseMRL: parse the options contained in the MRL
 *****************************************************************************/
static void ParseMRL( demux_sys_t *p_sys, char *psz_path, vlc_object_t *p_obj )
{
    char *psz_dup = strdup( psz_path );
757
758
759
760
761
762
763
764
765
766
767
768
769
    char *psz_parser = psz_dup;

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

    if( *psz_parser == ':' )
    {
        /* read options */
        for( ;; )
        {
            *psz_parser++ = '\0';
770

771
            if( !strncmp( psz_parser, "standard=", strlen( "standard=" ) ) )
772
773
            {
                psz_parser += strlen( "standard=" );
dionoea's avatar
dionoea committed
774
775
                size_t i;
                for( i = 0; i < ARRAY_SIZE(psz_standards_list_text); i++ )
776
                {
dionoea's avatar
dionoea committed
777
778
779
780
781
782
783
784
785
                    const char *psz_value = psz_standards_list_text[i];
                    size_t i_len = strlen( psz_value );
                    if( !strncasecmp( psz_parser, psz_value, i_len ) &&
                        ( psz_parser[i_len] == ':' || psz_parser[i_len] == 0 ) )
                    {
                        p_sys->i_selected_standard_id = i_standards_list[i];
                        psz_parser += i_len;
                        break;
                    }
786
                }
dionoea's avatar
dionoea committed
787
788

                if( i == ARRAY_SIZE(psz_standards_list_text) )
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
                    p_sys->i_selected_standard_id = i_standards_list[strtol( psz_parser, &psz_parser, 0 )];
            }
            else if( !strncmp( psz_parser, "chroma=", strlen( "chroma=" ) ) )
            {
                int  i_len;

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

805
                free( p_sys->psz_requested_chroma );
806
                p_sys->psz_requested_chroma = strndup( psz_parser, i_len );
807

808
                psz_parser += i_len;
809
810
811
812
813
            }
            else if( !strncmp( psz_parser, "input=", strlen( "input=" ) ) )
            {
                p_sys->i_selected_input = strtol( psz_parser + strlen( "input=" ),
                                       &psz_parser, 0 );
814
            }
815
816
817
818
819
            else if( !strncmp( psz_parser, "audio-input=", strlen( "audio-input=" ) ) )
            {
                p_sys->i_selected_audio_input = strtol( psz_parser + strlen( "audio-input=" ),
                                       &psz_parser, 0 );
            }
820
821
            else if( !strncmp( psz_parser, "fps=", strlen( "fps=" ) ) )
            {
822
823
                p_sys->f_fps = us_strtof( psz_parser + strlen( "fps=" ),
                                          &psz_parser );
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
            }
            else if( !strncmp( psz_parser, "io=", strlen( "io=" ) ) )
            {
                psz_parser += strlen( "io=" );
                if( !strncmp( psz_parser, "read", strlen( "read" ) ) )
                {
                    p_sys->io = IO_METHOD_READ;
                    psz_parser += strlen( "read" );
                }
                else if( !strncmp( psz_parser, "mmap", strlen( "mmap" ) ) )
                {
                    p_sys->io = IO_METHOD_MMAP;
                    psz_parser += strlen( "mmap" );
                }
                else if( !strncmp( psz_parser, "userptr", strlen( "userptr" ) ) )
                {
                    p_sys->io = IO_METHOD_USERPTR;
                    psz_parser += strlen( "userptr" );
                }
dionoea's avatar
dionoea committed
843
844
845
846
847
                else if( !strncmp( psz_parser, "auto", strlen( "auto" ) ) )
                {
                    p_sys->io = IO_METHOD_AUTO;
                    psz_parser += strlen( "auto" );
                }
848
849
850
851
852
                else
                {
                    p_sys->io = strtol( psz_parser, &psz_parser, 0 );
                }
            }
853
854
855
856
857
858
859
860
861
862
863
864
865
            else if( !strncmp( psz_parser, "width=",
                               strlen( "width=" ) ) )
            {
                p_sys->i_width =
                    strtol( psz_parser + strlen( "width=" ),
                            &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "height=",
                               strlen( "height=" ) ) )
            {
                p_sys->i_height =
                    strtol( psz_parser + strlen( "height=" ),
                            &psz_parser, 0 );
866
            }
867
868
869
870
871
872
873
874
875
876
877
            else if( !strncmp( psz_parser, "aspect-ratio=",
                               strlen( "aspect-ratio=" ) ) )
            {
                unsigned int num,den;
                num = strtol( psz_parser + strlen( "aspect-ratio=" ),
                              &psz_parser, 0 );
                den = strtol( psz_parser + strlen( ":" ),
                              &psz_parser, 0 );
                if( num && den )
                    p_sys->i_aspect = num * VOUT_ASPECT_FACTOR / den;
            }
878
879
            else if( !strncmp( psz_parser, "controls-reset",
                               strlen( "controls-reset" ) ) )
dionoea's avatar
dionoea committed
880
            {
881
                var_SetBool( p_obj, "v4l2-controls-reset", true );
882
                psz_parser += strlen( "controls-reset" );
dionoea's avatar
dionoea committed
883
            }
884
#if 0
885
886
887
            else if( !strncmp( psz_parser, "brightness=",
                               strlen( "brightness=" ) ) )
            {
888
                var_SetInteger( p_obj, "brightness",
889
                    strtol( psz_parser + strlen( "brightness=" ),
890
                            &psz_parser, 0 ) );
891
892
893
894
            }
            else if( !strncmp( psz_parser, "contrast=",
                               strlen( "contrast=" ) ) )
            {
895
                var_SetInteger( p_obj, "contrast",
896
                    strtol( psz_parser + strlen( "contrast=" ),
897
                            &psz_parser, 0 ) );
898
899
900
901
            }
            else if( !strncmp( psz_parser, "saturation=",
                               strlen( "saturation=" ) ) )
            {
902
                var_SetInteger( p_obj, "saturation",
903
                    strtol( psz_parser + strlen( "saturation=" ),
904
                            &psz_parser, 0 ) );
905
906
907
908
            }
            else if( !strncmp( psz_parser, "hue=",
                               strlen( "hue=" ) ) )
            {
909
                var_SetInteger( p_obj, "hue",
910
                    strtol( psz_parser + strlen( "hue=" ),
911
                            &psz_parser, 0 ) );
912
            }
913
914
915
            else if( !strncmp( psz_parser, "gamma=",
                               strlen( "gamma=" ) ) )
            {
916
                var_SetInteger( p_obj, "gamma",
917
                    strtol( psz_parser + strlen( "gamma=" ),
918
                            &psz_parser, 0 ) );
919
            }
920
#endif
921
922
            else if( !strncmp( psz_parser, "caching=", strlen( "caching=" ) ) )
            {
dionoea's avatar
dionoea committed
923
924
                p_sys->i_cache = strtol( psz_parser + strlen( "caching=" ),
                                         &psz_parser, 0 );
925
            }
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
            else if( !strncmp( psz_parser, "tuner=", strlen( "tuner=" ) ) )
            {
                p_sys->i_cur_tuner = strtol( psz_parser + strlen( "tuner=" ),
                                         &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "tuner-frequency=", strlen( "tuner-frequency=" ) ) )
            {
                p_sys->i_frequency = strtol( psz_parser
                                          + strlen( "tuner-frequency=" ),
                                          &psz_parser, 0 );
            }
            else if( !strncmp( psz_parser, "tuner-audio-mode=", strlen( "tuner-audio-mode=" ) ) )
            {
                p_sys->i_audio_mode = strtol( psz_parser
                                          + strlen( "tuner-audio-mode=" ),
                                          &psz_parser, 0 );
            }
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
            else if( !strncmp( psz_parser, "set-ctrls=", strlen( "set-ctrls=" )) )
            {
                int  i_len;

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

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

                psz_parser += i_len;
            }
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
            else if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) )
             || !strncmp( psz_parser, "samplerate=", strlen( "samplerate=" ) )
             || !strncmp( psz_parser, "audio-method", strlen( "audio-method" ) )
             || !strncmp( psz_parser, "stereo", strlen( "stereo" ) )
             || !strncmp( psz_parser, "mono", strlen( "mono" ) ) )
            {
                if( strchr( psz_parser, ':' ) )
                {
                    psz_parser = strchr( psz_parser, ':' );
                }
                else
                {
                    psz_parser += strlen( psz_parser );
                }

                msg_Err( p_obj, AUDIO_DEPRECATED_ERROR );
            }
978
979
            else
            {
980
981
982
983
984
985
986
                char *psz_unk = strchr( psz_parser, ':' );
                if (psz_unk)
                    psz_unk = strndup( psz_parser, psz_unk - psz_parser );
                else
                    psz_unk = strdup( psz_parser);
                msg_Warn( p_obj, "unknown option %s", psz_unk );
                free (psz_unk);
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
            }

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

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