video.c 48.8 KB
Newer Older
1 2 3
/*****************************************************************************
 * v4l2.c : Video4Linux2 input module for vlc
 *****************************************************************************
Antoine Cellerier's avatar
Antoine Cellerier 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 "v4l2.h"
41
#include <vlc_plugin.h>
42
#include <vlc_fs.h>
43
#include <vlc_demux.h>
44

45
#include <math.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
46
#include <assert.h>
47
#include <errno.h>
48 49
#include <fcntl.h>
#include <sys/ioctl.h>
50
#include <sys/mman.h>
51 52
#include <poll.h>

53 54
/*****************************************************************************
 * Module descriptior
55
 *****************************************************************************/
56

57 58 59
#define DEVICE_TEXT N_( "Device" )
#define DEVICE_LONGTEXT N_( \
    "Video device (Default: /dev/video0)." )
60 61 62 63 64 65
#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 " \
Antoine Cellerier's avatar
Antoine Cellerier committed
66
    "(eg. I420 or I422 for raw images, MJPG for M-JPEG compressed input) " \
67 68
    "(Complete list: GREY, I240, RV16, RV15, RV24, RV32, YUY2, YUYV, UYVY, " \
    "I41N, I422, I420, I411, I410, MJPG)")
Benjamin Pracht's avatar
Benjamin Pracht committed
69 70
#define INPUT_TEXT N_( "Input" )
#define INPUT_LONGTEXT N_( \
71 72 73 74
    "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)." )
75 76
#define WIDTH_TEXT N_( "Width" )
#define WIDTH_LONGTEXT N_( \
77
    "Force width (-1 for autodetect, 0 for driver default)." )
78 79
#define HEIGHT_TEXT N_( "Height" )
#define HEIGHT_LONGTEXT N_( \
80
    "Force height (-1 for autodetect, 0 for driver default)." )
81 82
#define FPS_TEXT N_( "Framerate" )
#define FPS_LONGTEXT N_( "Framerate to capture, if applicable " \
83
    "(0 for autodetect)." )
84

85 86 87 88 89 90
#ifdef HAVE_LIBV4L2
#define LIBV4L2_TEXT N_( "Use libv4l2" )
#define LIBV4L2_LONGTEXT N_( \
    "Force usage of the libv4l2 wrapper." )
#endif

91 92 93
#define CTRL_RESET_TEXT N_( "Reset v4l2 controls" )
#define CTRL_RESET_LONGTEXT N_( \
    "Reset controls to defaults provided by the v4l2 driver." )
94 95
#define BRIGHTNESS_TEXT N_( "Brightness" )
#define BRIGHTNESS_LONGTEXT N_( \
96
    "Brightness of the video input (if supported by the v4l2 driver)." )
97 98
#define CONTRAST_TEXT N_( "Contrast" )
#define CONTRAST_LONGTEXT N_( \
99
    "Contrast of the video input (if supported by the v4l2 driver)." )
100 101
#define SATURATION_TEXT N_( "Saturation" )
#define SATURATION_LONGTEXT N_( \
102
    "Saturation of the video input (if supported by the v4l2 driver)." )
103 104
#define HUE_TEXT N_( "Hue" )
#define HUE_LONGTEXT N_( \
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    "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)." )
123 124
#define GAMMA_TEXT N_( "Gamma" )
#define GAMMA_LONGTEXT N_( \
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    "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)." )
148

149 150
#define AUDIO_VOLUME_TEXT N_( "Volume" )
#define AUDIO_VOLUME_LONGTEXT N_( \
151
    "Volume of the audio input (if supported by the v4l2 driver)." )
152 153
#define AUDIO_BALANCE_TEXT N_( "Balance" )
#define AUDIO_BALANCE_LONGTEXT N_( \
154
    "Balance of the audio input (if supported by the v4l2 driver)." )
155 156
#define AUDIO_MUTE_TEXT N_( "Mute" )
#define AUDIO_MUTE_LONGTEXT N_( \
157 158 159 160 161 162 163 164 165 166 167
    "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)." )

168 169 170 171 172 173 174
#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." )
175

176 177 178 179 180 181 182 183 184 185
#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." )

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

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
static const v4l2_std_id standards_v4l2[] = { V4L2_STD_UNKNOWN, V4L2_STD_ALL,
    V4L2_STD_PAL,     V4L2_STD_PAL_BG,   V4L2_STD_PAL_DK,
    V4L2_STD_NTSC,
    V4L2_STD_SECAM,   V4L2_STD_SECAM_DK,
    V4L2_STD_525_60,  V4L2_STD_625_50,
    V4L2_STD_ATSC,

    V4L2_STD_MN,      V4L2_STD_B,        V4L2_STD_GH,       V4L2_STD_DK,

    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,
};
static const char *const standards_vlc[] = { "", "ALL",
    /* Pseudo standards */
    "PAL", "PAL_BG", "PAL_DK",
    "NTSC",
    "SECAM", "SECAM_DK",
    "525_60", "625_50",
    "ATSC",

    /* Areas (PAL/NTSC or PAL/SECAM) */
    "MN", "B", "GH", "DK",

    /* Individual standards */
    "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",
};
static const char *const standards_user[] = { N_("Undefined"), N_("All"),
    "PAL",            "PAL B/G",         "PAL D/K",
    "NTSC",
    "SECAM",          "SECAM D/K",
    N_("525 lines / 60 Hz"), N_("625 lines / 50 Hz"),
    "ATSC",

    "PAL/NTSC M/N",
    "PAL/SECAM B",    "PAL/SECAM G/H",   "PAL/SECAM D/K",

    "PAL B",          "PAL B1",          "PAL G",           "PAL H",
    "PAL I",          "PAL D",           "PAL D1",          "PAL K",
    "PAL M",          "PAL N",           N_("PAL N Argentina"), "PAL 60",
    "NTSC M",        N_("NTSC M Japan"), "NTSC 443",  N_("NTSC M South Korea"),
    "SECAM B",        "SECAM D",         "SECAM G",         "SECAM H",
    "SECAM K",        "SECAM K1",        "SECAM L",         "SECAM L/C",
    "ATSC 8-VSB",     "ATSC 16-VSB",
};
244

245 246
static const int i_tuner_audio_modes_list[] = {
      -1, V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO,
247 248
      V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2,
      V4L2_TUNER_MODE_SAP, V4L2_TUNER_MODE_LANG1_LANG2 };
249 250 251
static const char *const psz_tuner_audio_modes_list_text[] = {
      N_("Unspecified"),
      N_( "Mono" ),
252 253 254 255 256 257
      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 261 262 263 264 265 266 267 268 269
#ifdef HAVE_MAEMO
# define DEFAULT_WIDTH	640
# define DEFAULT_HEIGHT	492
#endif

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

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

276
    set_section( N_( "Video input" ), NULL )
277 278
    add_string( CFG_PREFIX "dev", "/dev/video0", DEVICE_TEXT, DEVICE_LONGTEXT,
                 false )
279
        change_safe()
280 281 282
    add_string( CFG_PREFIX "standard", "",
                STANDARD_TEXT, STANDARD_LONGTEXT, false )
        change_string_list( standards_vlc, standards_user, NULL )
283
        change_safe()
284
    add_string( CFG_PREFIX "chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
285
                true )
286
        change_safe()
287
    add_integer( CFG_PREFIX "input", 0, INPUT_TEXT, INPUT_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
288
                true )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
289
        change_integer_range( 0, 0xFFFFFFFE )
290
        change_safe()
291
    add_integer( CFG_PREFIX "audio-input", -1, AUDIO_INPUT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
292
                 AUDIO_INPUT_LONGTEXT, true )
293
        change_integer_range( -1, 0xFFFFFFFE )
294
        change_safe()
295
    add_obsolete_integer( CFG_PREFIX "io" ) /* since 1.2.0 */
296
    add_integer( CFG_PREFIX "width", DEFAULT_WIDTH, WIDTH_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
297
                WIDTH_LONGTEXT, true )
298
        change_safe()
299
    add_integer( CFG_PREFIX "height", DEFAULT_HEIGHT, HEIGHT_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
300
                HEIGHT_LONGTEXT, true )
301
        change_safe()
302
    add_string( CFG_PREFIX "aspect-ratio", "4:3", ASPECT_TEXT,
303
              ASPECT_LONGTEXT, true )
304
        change_safe()
305
    add_float( CFG_PREFIX "fps", 0, FPS_TEXT, FPS_LONGTEXT, true )
306
        change_safe()
307
#ifdef HAVE_LIBV4L2
308
    add_bool( CFG_PREFIX "use-libv4l2", false, LIBV4L2_TEXT, LIBV4L2_LONGTEXT, true );
309
#endif
310

311
    set_section( N_( "Tuner" ), NULL )
312
    add_integer( CFG_PREFIX "tuner", 0, TUNER_TEXT, TUNER_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
313
                 true )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
314
        change_integer_range( 0, 0xFFFFFFFE )
315
        change_safe()
316
    add_integer( CFG_PREFIX "tuner-frequency", -1, FREQUENCY_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
317
                 FREQUENCY_LONGTEXT, true )
318
        change_integer_range( -1, 0xFFFFFFFE )
319
        change_safe()
320
    add_integer( CFG_PREFIX "tuner-audio-mode", -1, TUNER_AUDIO_MODE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
321
                 TUNER_AUDIO_MODE_LONGTEXT, true )
322
        change_integer_list( i_tuner_audio_modes_list,
323
                             psz_tuner_audio_modes_list_text )
324
        change_safe()
325

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
381 382 383 384
    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" )
385

386
    add_shortcut( "v4l2" )
387
    set_capability( "access_demux", 0 )
388
    set_callbacks( DemuxOpen, DemuxClose )
389

390
    add_submodule ()
391
    add_shortcut( "v4l2", "v4l2c" )
392 393
    set_description( N_("Video4Linux2 Compressed A/V") )
    set_capability( "access", 0 )
394
    /* use these when open as access_demux fails; VLC will use another demux */
395
    set_callbacks( AccessOpen, AccessClose )
396

397
vlc_module_end ()
398 399 400 401 402

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

403
static block_t* ProcessVideoFrame( vlc_object_t *p_demux, uint8_t *p_frame, size_t );
Benjamin Pracht's avatar
Benjamin Pracht committed
404

405
static const struct
406
{
407
    unsigned int i_v4l2;
408
    vlc_fourcc_t i_fourcc;
409 410 411
    int i_rmask;
    int i_gmask;
    int i_bmask;
412 413
} v4l2chroma_to_fourcc[] =
{
414
    /* Raw data types */
415
    { V4L2_PIX_FMT_GREY,    VLC_CODEC_GREY, 0, 0, 0 },
416
    { V4L2_PIX_FMT_HI240,   VLC_FOURCC('I','2','4','0'), 0, 0, 0 },
417 418
    { V4L2_PIX_FMT_RGB555,  VLC_CODEC_RGB15, 0x001f,0x03e0,0x7c00 },
    { V4L2_PIX_FMT_RGB565,  VLC_CODEC_RGB16, 0x001f,0x07e0,0xf800 },
419 420
    /* Won't work since we don't know how to handle such gmask values
     * correctly
421 422
    { V4L2_PIX_FMT_RGB555X, VLC_CODEC_RGB15, 0x007c,0xe003,0x1f00 },
    { V4L2_PIX_FMT_RGB565X, VLC_CODEC_RGB16, 0x00f8,0xe007,0x1f00 },
423
    */
424 425 426 427 428 429
    { 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 },
430
    { V4L2_PIX_FMT_Y41P,    VLC_FOURCC('I','4','1','N'), 0, 0, 0 },
431 432 433 434
    { 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 },
435 436 437

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

441
    /* Compressed data types */
442
    { V4L2_PIX_FMT_MJPEG,   VLC_CODEC_MJPG, 0, 0, 0 },
443
    { V4L2_PIX_FMT_JPEG,    VLC_CODEC_JPEG, 0, 0, 0 },
444 445 446 447
#if 0
    { V4L2_PIX_FMT_DV,      VLC_FOURCC('?','?','?','?') },
    { V4L2_PIX_FMT_MPEG,    VLC_FOURCC('?','?','?','?') },
#endif
448
    { 0, 0, 0, 0, 0 }
449
};
450

451 452 453
/**
 * List of V4L2 chromas were confident enough to use as fallbacks if the
 * user hasn't provided a --v4l2-chroma value.
454 455
 *
 * Try YUV chromas first, then RGB little endian and MJPEG as last resort.
456
 */
457
static const uint32_t p_chroma_fallbacks[] =
458
{ V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV422P,
459
  V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_BGR24,
460
  V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG };
461

462
/**
463
 * Parses a V4L2 MRL into VLC object variables.
464
 */
465
void ParseMRL( vlc_object_t *obj, const char *mrl )
466
{
467
    const char *p = strchr( mrl, ':' );
468
    char *dev = NULL;
469

470
    if( p != NULL )
471
    {
472 473
        var_LocationParse( obj, p + 1, CFG_PREFIX );
        if( p > mrl )
474
            dev = strndup( mrl, p - mrl );
475
    }
476
    else
477
    {
478
        if( mrl[0] )
479 480 481 482 483 484 485 486
            dev = strdup( mrl );
    }

    if( dev != NULL )
    {
        var_Create( obj, CFG_PREFIX"dev", VLC_VAR_STRING );
        var_SetString( obj, CFG_PREFIX"dev", dev );
        free( dev );
487
    }
488 489 490 491 492
}

/*****************************************************************************
 * GrabVideo: Grab a video frame
 *****************************************************************************/
493
block_t* GrabVideo( vlc_object_t *p_demux, demux_sys_t *p_sys )
494
{
495
    block_t *p_block;
496 497 498 499 500 501 502 503 504
    struct v4l2_buffer buf;

    /* Grab Video Frame */
    switch( p_sys->io )
    {
    case IO_METHOD_MMAP:
        memset( &buf, 0, sizeof(buf) );
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
505

506
        /* Wait for next frame */
507
        if (v4l2_ioctl( p_sys->i_fd, VIDIOC_DQBUF, &buf ) < 0 )
508
        {
509
            switch( errno )
510 511
            {
            case EAGAIN:
Rémi Duraffort's avatar
Rémi Duraffort committed
512
                return NULL;
513 514 515 516 517
            case EIO:
                /* Could ignore EIO, see spec. */
                /* fall through */
            default:
                msg_Err( p_demux, "Failed to wait (VIDIOC_DQBUF)" );
Rémi Duraffort's avatar
Rémi Duraffort committed
518
                return NULL;
519
               }
520 521 522 523
        }

        if( buf.index >= p_sys->i_nbuffers ) {
            msg_Err( p_demux, "Failed capturing new frame as i>=nbuffers" );
Rémi Duraffort's avatar
Rémi Duraffort committed
524
            return NULL;
525
        }
526

527
        p_block = ProcessVideoFrame( p_demux, p_sys->p_buffers[buf.index].start, buf.bytesused );
Rémi Duraffort's avatar
Rémi Duraffort committed
528 529
        if( !p_block )
            return NULL;
530

531
        /* Unlock */
532
        if( v4l2_ioctl( p_sys->i_fd, VIDIOC_QBUF, &buf ) < 0 )
533
        {
534 535
            msg_Err( p_demux, "Failed to unlock (VIDIOC_QBUF)" );
            block_Release( p_block );
Rémi Duraffort's avatar
Rémi Duraffort committed
536
            return NULL;
537
        }
538

539
        break;
540 541

    case IO_METHOD_USERPTR:
542 543 544
        memset( &buf, 0, sizeof(buf) );
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_USERPTR;
545

546
        /* Wait for next frame */
547
        if (v4l2_ioctl( p_sys->i_fd, VIDIOC_DQBUF, &buf ) < 0 )
548
        {
549
            switch( errno )
550 551
            {
            case EAGAIN:
Rémi Duraffort's avatar
Rémi Duraffort committed
552
                return NULL;
553 554 555 556 557
            case EIO:
                /* Could ignore EIO, see spec. */
                /* fall through */
            default:
                msg_Err( p_demux, "Failed to wait (VIDIOC_DQBUF)" );
Rémi Duraffort's avatar
Rémi Duraffort committed
558
                return NULL;
559
            }
560 561 562 563 564 565
        }

        /* Find frame? */
        unsigned int i;
        for( i = 0; i < p_sys->i_nbuffers; i++ )
        {
566
            if( buf.m.userptr == (unsigned long)p_sys->p_buffers[i].start &&
567 568 569
                buf.length == p_sys->p_buffers[i].length ) break;
        }

570
        if( i >= p_sys->i_nbuffers )
571
        {
572
            msg_Err( p_demux, "Failed capturing new frame as i>=nbuffers" );
Rémi Duraffort's avatar
Rémi Duraffort committed
573
            return NULL;
574
        }
575

576
        p_block = ProcessVideoFrame( p_demux, (uint8_t*)buf.m.userptr, buf.bytesused );
Rémi Duraffort's avatar
Rémi Duraffort committed
577 578
        if( !p_block )
            return NULL;
579

580
        /* Unlock */
581
        if( v4l2_ioctl( p_sys->i_fd, VIDIOC_QBUF, &buf ) < 0 )
582
        {
583 584
            msg_Err( p_demux, "Failed to unlock (VIDIOC_QBUF)" );
            block_Release( p_block );
Rémi Duraffort's avatar
Rémi Duraffort committed
585
            return NULL;
586 587
        }
        break;
588 589
    default:
        assert(0);
590 591 592 593 594 595 596 597
    }
    return p_block;
}

/*****************************************************************************
 * ProcessVideoFrame: Helper function to take a buffer and copy it into
 * a new block
 *****************************************************************************/
598
static block_t* ProcessVideoFrame( vlc_object_t *p_demux, uint8_t *p_frame, size_t i_size )
599 600 601
{
    block_t *p_block;

Rémi Duraffort's avatar
Rémi Duraffort committed
602
    if( !p_frame ) return NULL;
603

604
    /* New block */
605
    if( !( p_block = block_New( p_demux, i_size ) ) )
606 607
    {
        msg_Warn( p_demux, "Cannot get new block" );
Rémi Duraffort's avatar
Rémi Duraffort committed
608
        return NULL;
609 610 611
    }

    /* Copy frame */
612
    memcpy( p_block->p_buffer, p_frame, i_size );
613

614 615 616 617 618 619
    return p_block;
}

/*****************************************************************************
 * Helper function to initalise video IO using the mmap method
 *****************************************************************************/
620
static int InitMmap( vlc_object_t *p_demux, demux_sys_t *p_sys, int i_fd )
621 622
{
    struct v4l2_requestbuffers req;
623

624 625 626 627
    memset( &req, 0, sizeof(req) );
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
628

629
    if( v4l2_ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 )
630
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
631 632
        msg_Err( p_demux, "device does not support mmap I/O" );
        return -1;
633
    }
634

635 636
    if( req.count < 2 )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
637 638
        msg_Err( p_demux, "insufficient buffers" );
        return -1;
639
    }
640

641
    p_sys->p_buffers = calloc( req.count, sizeof( *p_sys->p_buffers ) );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
642 643
    if( unlikely(!p_sys->p_buffers) )
        return -1;
644

645 646 647
    for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < req.count; ++p_sys->i_nbuffers )
    {
        struct v4l2_buffer buf;
Rafaël Carré's avatar
Rafaël Carré committed
648

649 650 651 652
        memset( &buf, 0, sizeof(buf) );
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = p_sys->i_nbuffers;
653

654
        if( v4l2_ioctl( i_fd, VIDIOC_QUERYBUF, &buf ) < 0 )
655
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
656 657
            msg_Err( p_demux, "VIDIOC_QUERYBUF: %m" );
            return -1;
658
        }
659

660
        p_sys->p_buffers[p_sys->i_nbuffers].length = buf.length;
661
        p_sys->p_buffers[p_sys->i_nbuffers].start =
662
            v4l2_mmap( NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, i_fd, buf.m.offset );
663 664 665

        if( p_sys->p_buffers[p_sys->i_nbuffers].start == MAP_FAILED )
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
666 667
            msg_Err( p_demux, "mmap failed: %m" );
            return -1;
668 669
        }
    }
670

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
671
    return 0;
672 673 674 675 676
}

/*****************************************************************************
 * Helper function to initalise video IO using the userbuf method
 *****************************************************************************/
677
static int InitUserP( vlc_object_t *p_demux, demux_sys_t *p_sys, int i_fd, unsigned int i_buffer_size )
678 679
{
    struct v4l2_requestbuffers req;
680 681
    unsigned int i_page_size;

682
    i_page_size = sysconf(_SC_PAGESIZE);
683
    i_buffer_size = ( i_buffer_size + i_page_size - 1 ) & ~( i_page_size - 1);
684

685 686 687 688
    memset( &req, 0, sizeof(req) );
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_USERPTR;
689

690
    if( v4l2_ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 )
691 692
    {
        msg_Err( p_demux, "device does not support user pointer i/o" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
693
        return -1;
694
    }
695

696 697
    p_sys->p_buffers = calloc( 4, sizeof( *p_sys->p_buffers ) );
    if( !p_sys->p_buffers )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
698
        return -1;
699

700 701 702
    for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < 4; ++p_sys->i_nbuffers )
    {
        p_sys->p_buffers[p_sys->i_nbuffers].length = i_buffer_size;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
703 704
        if( posix_memalign( &p_sys->p_buffers[p_sys->i_nbuffers].start,
                /* boundary */ i_page_size, i_buffer_size ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
705
            return -1;
706 707
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
708
    return 0;
709 710
}

711 712
/**
 * \return true if the specified V4L2 pixel format is
713
 * in the array of supported formats returned by the driver
714 715 716
 */
static bool IsPixelFormatSupported( struct v4l2_fmtdesc *codecs, size_t n,
                                    unsigned int i_pixelformat )
717
{
718 719
    for( size_t i = 0; i < n; i++ )
        if( codecs[i].pixelformat == i_pixelformat )
720 721
            return true;
    return false;
722
}
723

724

725 726 727
static int InitVideo( vlc_object_t *p_obj, int i_fd, demux_sys_t *p_sys,
                      bool b_demux );

728 729 730 731
/**
 * Opens and sets up a video device
 * \return file descriptor or -1 on error
 */
732
int OpenVideo( vlc_object_t *obj, demux_sys_t *sys, bool b_demux )
733
{
734
    char *path = var_InheritString( obj, CFG_PREFIX"dev" );
735 736 737
    if( unlikely(path == NULL) )
        return -1; /* probably OOM */

738
    msg_Dbg( obj, "opening device '%s'", path );
739

740 741
    int fd = vlc_open( path, O_RDWR );
    if( fd == -1 )
Benjamin Pracht's avatar
Benjamin Pracht committed
742
    {
743
        msg_Err( obj, "cannot open device '%s': %m", path );
744
        free( path );
745
        return -1;
Benjamin Pracht's avatar
Benjamin Pracht committed
746
    }
747
    free( path );
Antoine Cellerier's avatar
Antoine Cellerier committed
748
#ifdef HAVE_LIBV4L2
749 750 751 752 753 754 755
    if( !var_InheritBool( obj, CFG_PREFIX "use-libv4l2" ) )
    {
        msg_Dbg( obj, "trying kernel V4L2" );
        if( InitVideo( obj, fd, sys, b_demux ) == 0 )
            return fd;
    }
    msg_Dbg( obj, "trying library V4L2" );
756 757 758 759 760 761
    /* Note the v4l2_xxx functions are designed so that if they get passed an
       unknown fd, the will behave exactly as their regular xxx counterparts,
       so if v4l2_fd_open fails, we continue as normal (missing the libv4l2
       custom cam format to normal formats conversion). Chances are big we will
       still fail then though, as normally v4l2_fd_open only fails if the
       device is not a v4l2 device. */
762 763 764 765
    int libfd = v4l2_fd_open( fd, 0 );
    if( libfd == -1 )
        goto error;
    fd = libfd;
Antoine Cellerier's avatar
Antoine Cellerier committed
766
#endif
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
    if( InitVideo( obj, fd, sys, b_demux ) )
        goto error;

    return fd;
error:
    close( fd );
    return -1;
}

static int InitVideo( vlc_object_t *p_obj, int i_fd, demux_sys_t *p_sys,
                      bool b_demux )
{
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    struct v4l2_format fmt;
    unsigned int i_min;
    enum v4l2_buf_type buf_type;
    es_format_t es_fmt;
785

786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
    /* Get device capabilites */
    struct v4l2_capability cap;
    if( v4l2_ioctl( i_fd, VIDIOC_QUERYCAP, &cap ) < 0 )
    {
        msg_Err( p_obj, "cannot get video capabilities: %m" );
        return -1;
    }

    msg_Dbg( p_obj, "device %s using driver %s (version %u.%u.%u) on %s",
            cap.card, cap.driver, (cap.version >> 16) & 0xFF,
            (cap.version >> 8) & 0xFF, cap.version & 0xFF, cap.bus_info );
    msg_Dbg( p_obj, "the device has the capabilities: 0x%08X",
             cap.capabilities );
    msg_Dbg( p_obj, " (%c) Video Capture, (%c) Audio, (%c) Tuner, (%c) Radio",
             ( cap.capabilities & V4L2_CAP_VIDEO_CAPTURE  ? 'X':' '),
             ( cap.capabilities & V4L2_CAP_AUDIO  ? 'X':' '),
             ( cap.capabilities & V4L2_CAP_TUNER  ? 'X':' '),
             ( cap.capabilities & V4L2_CAP_RADIO  ? 'X':' ') );
    msg_Dbg( p_obj, " (%c) Read/Write, (%c) Streaming, (%c) Asynchronous",
            ( cap.capabilities & V4L2_CAP_READWRITE ? 'X':' ' ),
            ( cap.capabilities & V4L2_CAP_STREAMING ? 'X':' ' ),
            ( cap.capabilities & V4L2_CAP_ASYNCIO ? 'X':' ' ) );
808

809 810 811 812 813
    if( cap.capabilities & V4L2_CAP_STREAMING )
        p_sys->io = IO_METHOD_MMAP;
    else if( cap.capabilities & V4L2_CAP_READWRITE )
        p_sys->io = IO_METHOD_READ;
    else
814
    {
815
        msg_Err( p_obj, "no supported I/O method" );
816
        return -1;
817
    }
818 819 820 821 822 823 824

    /* Now, enumerate all the video inputs. This is useless at the moment
       since we have no way to present that info to the user except with
       debug messages */
    if( cap.capabilities & V4L2_CAP_VIDEO_CAPTURE )
    {
        struct v4l2_input input;
825 826
        unsigned index = var_InheritInteger( p_obj, CFG_PREFIX"input" );

827 828 829 830 831 832 833
        input.index = 0;
        while( v4l2_ioctl( i_fd, VIDIOC_ENUMINPUT, &input ) >= 0 )
        {
            msg_Dbg( p_obj, "video input %u (%s) has type: %s %c",
                     input.index, input.name,
                     input.type == V4L2_INPUT_TYPE_TUNER
                          ? "Tuner adapter" : "External analog input",
834
                     input.index == index ? '*' : ' ' );
835 836 837 838
            input.index++;
        }

        /* Select input */
839
        if( v4l2_ioctl( i_fd, VIDIOC_S_INPUT, &index ) < 0 )
840
        {
841
            msg_Err( p_obj, "cannot set input %u: %m", index );
842
            return -1;
843
        }
844
        msg_Dbg( p_obj, "input set to %u", index );
845
    }
846

847
    /* Select standard */
848
    bool bottom_first;
849
    const char *stdname = var_InheritString( p_obj, CFG_PREFIX"standard" );
850
    if( stdname != NULL )
851
    {
852 853 854 855 856 857 858 859 860 861 862 863 864 865
        v4l2_std_id std = strtoull( stdname, NULL, 0 );
        if( std == 0 )
        {
            const size_t n = sizeof(standards_vlc) / sizeof(*standards_vlc);
            assert( n == sizeof(standards_v4l2) / sizeof(*standards_v4l2) );
            assert( n == sizeof(standards_user) / sizeof(*standards_user) );
            for( size_t i = 0; i < n; i++ )
                if( strcasecmp( stdname, standards_vlc[i] ) == 0 )
                {
                    std = standards_v4l2[i];
                    break;
                }
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
866 867
        if( v4l2_ioctl( i_fd, VIDIOC_S_STD, &std ) < 0
         || v4l2_ioctl( i_fd,