pvr.c 33.2 KB
Newer Older
1
2
3
/*****************************************************************************
 * pvr.c
 *****************************************************************************
4
 * Copyright (C) 2001, 2002 the VideoLAN team
5
 * $Id$
6
7
 *
 * Authors: Eric Petit <titer@videolan.org>
8
 *          Paul Corke <paulc@datatote.co.uk>
9
10
11
12
13
 *
 * 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.
14
 *
15
16
17
18
19
20
21
 * 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
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28
29
30
31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
34
#include <vlc_access.h>
35
#include <vlc_fs.h>
36
37
38
39
40
41

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
#include <sys/ioctl.h>
42
#include <sys/poll.h>
43
#ifdef HAVE_NEW_LINUX_VIDEODEV2_H
44
45
46
47
48
#   ifdef VIDEODEV2_H_FILE
#   include VIDEODEV2_H_FILE
#   else
#   include <linux/videodev2.h>
#   endif
49
#else
50
#include "videodev2.h"
51
#endif
52
53
54
55

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
56
57
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
58

59
60
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
zorglub's avatar
zorglub committed
61
62
    "Default caching value for PVR streams. This " \
    "value should be set in milliseconds." )
63

64
65
66
#define DEVICE_TEXT N_( "Device" )
#define DEVICE_LONGTEXT N_( "PVR video device" )

67
68
69
#define RADIO_DEVICE_TEXT N_( "Radio device" )
#define RADIO_DEVICE_LONGTEXT N_( "PVR radio device" )

70
#define NORM_TEXT N_( "Norm" )
zorglub's avatar
zorglub committed
71
72
#define NORM_LONGTEXT N_( "Norm of the stream " \
    "(Automatic, SECAM, PAL, or NTSC)." )
73
74

#define WIDTH_TEXT N_( "Width" )
75
#define WIDTH_LONGTEXT N_( "Width of the stream to capture " \
zorglub's avatar
zorglub committed
76
    "(-1 for autodetection)." )
77

78
#define HEIGHT_TEXT N_( "Height" )
79
#define HEIGHT_LONGTEXT N_( "Height of the stream to capture " \
zorglub's avatar
zorglub committed
80
    "(-1 for autodetection)." )
81

82
#define FREQUENCY_TEXT N_( "Frequency" )
zorglub's avatar
zorglub committed
83
#define FREQUENCY_LONGTEXT N_( "Frequency to capture (in kHz), if applicable." )
84

85
#define FRAMERATE_TEXT N_( "Framerate" )
86
#define FRAMERATE_LONGTEXT N_( "Framerate to capture, if applicable " \
zorglub's avatar
zorglub committed
87
    "(-1 for autodetect)." )
88

89
#define KEYINT_TEXT N_( "Key interval" )
zorglub's avatar
zorglub committed
90
#define KEYINT_LONGTEXT N_( "Interval between keyframes (-1 for autodetect)." )
91

92
#define BFRAMES_TEXT N_( "B Frames" )
Felix Paul Kühne's avatar
Felix Paul Kühne committed
93
#define BFRAMES_LONGTEXT N_("If this option is set, B-Frames will be used. " \
94
95
    "Use this option to set the number of B-Frames.")

96
#define BITRATE_TEXT N_( "Bitrate" )
zorglub's avatar
zorglub committed
97
#define BITRATE_LONGTEXT N_( "Bitrate to use (-1 for default)." )
98

99
#define BITRATE_PEAK_TEXT N_( "Bitrate peak" )
zorglub's avatar
zorglub committed
100
#define BITRATE_PEAK_LONGTEXT N_( "Peak bitrate in VBR mode." )
101

Christophe Mutricy's avatar
Christophe Mutricy committed
102
#define BITRATE_MODE_TEXT N_( "Bitrate mode" )
zorglub's avatar
zorglub committed
103
#define BITRATE_MODE_LONGTEXT N_( "Bitrate mode to use (VBR or CBR)." )
104

105
#define BITMASK_TEXT N_( "Audio bitmask" )
zorglub's avatar
zorglub committed
106
#define BITMASK_LONGTEXT N_("Bitmask that will "\
107
108
    "get used by the audio part of the card." )

109
#define VOLUME_TEXT N_( "Volume" )
zorglub's avatar
zorglub committed
110
#define VOLUME_LONGTEXT N_("Audio volume (0-65535)." )
111

112
113
#define CHAN_TEXT N_( "Channel" )
#define CHAN_LONGTEXT N_( "Channel of the card to use (Usually, 0 = tuner, " \
114
115
    "1 = composite, 2 = svideo)" )

116
static const int i_norm_list[] =
117
    { V4L2_STD_UNKNOWN, V4L2_STD_SECAM, V4L2_STD_PAL, V4L2_STD_NTSC };
118
static const char *const psz_norm_list_text[] =
119
    { N_("Automatic"), N_("SECAM"), N_("PAL"),  N_("NTSC") };
120

121
122
static const int i_bitrates[] = { 0, 1 };
static const char *const psz_bitrates_list_text[] = { N_("vbr"), N_("cbr") };
123

124
static const int pi_radio_range[2] = { 65000, 108000 };
125

126
127
128
129
130
131
132
vlc_module_begin ()
    set_shortname( N_("PVR") )
    set_description( N_("IVTV MPEG Encoding cards input") )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACCESS )
    set_capability( "access", 0 )
    add_shortcut( "pvr" )
133

134
    add_integer( "pvr-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
135
                 CACHING_LONGTEXT, true )
136
    add_string( "pvr-device", "/dev/video0", NULL, DEVICE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
137
                 DEVICE_LONGTEXT, false )
138
    add_string( "pvr-radio-device", "/dev/radio0", NULL, RADIO_DEVICE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
139
                 RADIO_DEVICE_LONGTEXT, false )
140
    add_integer( "pvr-norm", V4L2_STD_UNKNOWN , NULL, NORM_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
141
142
                 NORM_LONGTEXT, false )
       change_integer_list( i_norm_list, psz_norm_list_text, NULL )
143
    add_integer( "pvr-width", -1, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, true )
bigben's avatar
bigben committed
144
    add_integer( "pvr-height", -1, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
145
                 true )
146
    add_integer( "pvr-frequency", -1, NULL, FREQUENCY_TEXT, FREQUENCY_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
147
                 false )
148
    add_integer( "pvr-framerate", -1, NULL, FRAMERATE_TEXT, FRAMERATE_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
149
                 true )
150
    add_integer( "pvr-keyint", -1, NULL, KEYINT_TEXT, KEYINT_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
151
                 true )
152
    add_integer( "pvr-bframes", -1, NULL, FRAMERATE_TEXT, FRAMERATE_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
153
                 true )
154
    add_integer( "pvr-bitrate", -1, NULL, BITRATE_TEXT, BITRATE_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
155
                 false )
156
    add_integer( "pvr-bitrate-peak", -1, NULL, BITRATE_PEAK_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
157
                 BITRATE_PEAK_LONGTEXT, true )
158
    add_integer( "pvr-bitrate-mode", -1, NULL, BITRATE_MODE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
159
160
                 BITRATE_MODE_LONGTEXT, true )
        change_integer_list( i_bitrates, psz_bitrates_list_text, NULL )
161
    add_integer( "pvr-audio-bitmask", -1, NULL, BITMASK_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
162
                 BITMASK_LONGTEXT, true )
163
    add_integer( "pvr-audio-volume", -1, NULL, VOLUME_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
164
                 VOLUME_LONGTEXT, true )
165
    add_integer( "pvr-channel", -1, NULL, CHAN_TEXT, CHAN_LONGTEXT, true )
166

167
168
    set_callbacks( Open, Close )
vlc_module_end ()
169

170
/*****************************************************************************
171
 * Prototypes
172
 *****************************************************************************/
173
static ssize_t Read   ( access_t *, uint8_t *, size_t );
174
175
176
177
178
179
180
181
182
static int Control( access_t *, int, va_list );

/* ivtv specific ioctls */
#define IVTV_IOC_G_CODEC    0xFFEE7703
#define IVTV_IOC_S_CODEC    0xFFEE7704

/* for use with IVTV_IOC_G_CODEC and IVTV_IOC_S_CODEC */

struct ivtv_ioctl_codec {
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    uint32_t aspect;
    uint32_t audio_bitmask;
    uint32_t bframes;
    uint32_t bitrate_mode;
    uint32_t bitrate;
    uint32_t bitrate_peak;
    uint32_t dnr_mode;
    uint32_t dnr_spatial;
    uint32_t dnr_temporal;
    uint32_t dnr_type;
    uint32_t framerate;
    uint32_t framespergop;
    uint32_t gop_closure;
    uint32_t pulldown;
    uint32_t stream_type;
198
199
};

200
201
202
203
struct access_sys_t
{
    /* file descriptor */
    int i_fd;
204
    int i_radio_fd;
205

206
207
208
    char *psz_videodev;
    char *psz_radiodev;

209
210
211
212
213
214
    /* options */
    int i_standard;
    int i_width;
    int i_height;
    int i_frequency;
    int i_framerate;
215
    int i_keyint;
216
    int i_bframes;
217
218
    int i_bitrate;
    int i_bitrate_peak;
bigben's avatar
-pvr.c    
bigben committed
219
    int i_bitrate_mode;
220
    int i_audio_bitmask;
221
    int i_input;
222
    int i_volume;
223
224

    /* driver version */
225
    bool b_v4l2_api;
226
227
};

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
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
369
370
371
372
373
374
375
376
377
378
379
380
381
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
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
/*****************************************************************************
 * ConfigureIVTV: set up codec parameters using the old ivtv api
 *****************************************************************************/
static int ConfigureIVTV( access_t * p_access )
{
    access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
    struct ivtv_ioctl_codec codec;
    int result;

    memset( &codec, 0, sizeof(struct ivtv_ioctl_codec) );

    result = ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec );
    if( result < 0 )
    {
        msg_Err( p_access, "Failed to read current capture card settings." );
        return VLC_EGENERIC;
    }

    if( p_sys->i_framerate != -1 )
    {
        switch( p_sys->i_framerate )
        {
            case 30:
                codec.framerate = 0;
                break;

            case 25:
                codec.framerate = 1;
                break;

            default:
                msg_Warn( p_access, "Invalid framerate, reverting to 25." );
                codec.framerate = 1;
                break;
        }
    }

    if( p_sys->i_bitrate != -1 )
    {
        codec.bitrate = p_sys->i_bitrate;
    }

    if( p_sys->i_bitrate_peak != -1 )
    {
        codec.bitrate_peak = p_sys->i_bitrate_peak;
    }

    if( p_sys->i_bitrate_mode != -1 )
    {
        codec.bitrate_mode = p_sys->i_bitrate_mode;
    }

    if( p_sys->i_audio_bitmask != -1 )
    {
        codec.audio_bitmask = p_sys->i_audio_bitmask;
    }

    if( p_sys->i_keyint != -1 )
    {
        codec.framespergop = p_sys->i_keyint;
    }

    if( p_sys->i_bframes != -1 )
    {
        codec.bframes = p_sys->i_bframes;
    }

    result = ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec );
    if( result  < 0 )
    {
        msg_Err( p_access, "Failed to write new capture card settings." );
        return VLC_EGENERIC;
    }

    msg_Dbg( p_access, "Setting codec parameters to:  framerate: "
                        "%d, bitrate: %d/%d/%d",
                        codec.framerate, codec.bitrate,
                        codec.bitrate_peak, codec.bitrate_mode );
    return VLC_SUCCESS;
}

#ifdef HAVE_NEW_LINUX_VIDEODEV2_H

#define MAX_V4L2_CTRLS (6)
/*****************************************************************************
 * AddV4L2Ctrl: adds a control to the v4l2 controls list
 *****************************************************************************/
static void AddV4L2Ctrl( access_t * p_access,
                         struct v4l2_ext_controls * p_controls,
                         uint32_t i_id, uint32_t i_value )
{
    if( p_controls->count >= MAX_V4L2_CTRLS )
    {
        msg_Err( p_access, "Tried to set too many v4l2 controls at once." );
        return;
    }

    p_controls->controls[p_controls->count].id    = i_id;
    p_controls->controls[p_controls->count].value = i_value;
    p_controls->count++;
}

/*****************************************************************************
 * V4L2SampleRate: calculate v4l2 sample rate from pvr-audio-bitmask
 *****************************************************************************/
static uint32_t V4L2SampleRate( uint32_t i_bitmask )
{
    switch( i_bitmask & 0x0003 )
    {
        case 0x0001: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
        case 0x0002: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
    }
    return V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
}

/*****************************************************************************
 * V4L2AudioEncoding: calculate v4l2 audio encoding level from pvr-audio-bitmask
 *****************************************************************************/
static uint32_t V4L2AudioEncoding( uint32_t i_bitmask )
{
    switch( i_bitmask & 0x000c )
    {
        case 0x0004: return V4L2_MPEG_AUDIO_ENCODING_LAYER_1;
        case 0x0008: return V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
    }
    return 0xffffffff;
}

/*****************************************************************************
 * V4L2AudioL1Bitrate: calculate v4l2 audio bitrate for layer-1 audio from pvr-audio-bitmask
 *****************************************************************************/
static uint32_t V4L2AudioL1Bitrate( uint32_t i_bitmask )
{
    switch( i_bitmask & 0x00f0 )
    {
        case 0x0010: return V4L2_MPEG_AUDIO_L1_BITRATE_32K;
        case 0x0020: return V4L2_MPEG_AUDIO_L1_BITRATE_64K;
        case 0x0030: return V4L2_MPEG_AUDIO_L1_BITRATE_96K;
        case 0x0040: return V4L2_MPEG_AUDIO_L1_BITRATE_128K;
        case 0x0050: return V4L2_MPEG_AUDIO_L1_BITRATE_160K;
        case 0x0060: return V4L2_MPEG_AUDIO_L1_BITRATE_192K;
        case 0x0070: return V4L2_MPEG_AUDIO_L1_BITRATE_224K;
        case 0x0080: return V4L2_MPEG_AUDIO_L1_BITRATE_256K;
        case 0x0090: return V4L2_MPEG_AUDIO_L1_BITRATE_288K;
        case 0x00a0: return V4L2_MPEG_AUDIO_L1_BITRATE_320K;
        case 0x00b0: return V4L2_MPEG_AUDIO_L1_BITRATE_352K;
        case 0x00c0: return V4L2_MPEG_AUDIO_L1_BITRATE_384K;
        case 0x00d0: return V4L2_MPEG_AUDIO_L1_BITRATE_416K;
        case 0x00e0: return V4L2_MPEG_AUDIO_L1_BITRATE_448K;
    }
    return V4L2_MPEG_AUDIO_L1_BITRATE_320K;
}

/*****************************************************************************
 * V4L2AudioL2Bitrate: calculate v4l2 audio bitrate for layer-1 audio from pvr-audio-bitmask
 *****************************************************************************/
static uint32_t V4L2AudioL2Bitrate( uint32_t i_bitmask )
{
    switch( i_bitmask & 0x00f0 )
    {
        case 0x0010: return V4L2_MPEG_AUDIO_L2_BITRATE_32K;
        case 0x0020: return V4L2_MPEG_AUDIO_L2_BITRATE_48K;
        case 0x0030: return V4L2_MPEG_AUDIO_L2_BITRATE_56K;
        case 0x0040: return V4L2_MPEG_AUDIO_L2_BITRATE_64K;
        case 0x0050: return V4L2_MPEG_AUDIO_L2_BITRATE_80K;
        case 0x0060: return V4L2_MPEG_AUDIO_L2_BITRATE_96K;
        case 0x0070: return V4L2_MPEG_AUDIO_L2_BITRATE_112K;
        case 0x0080: return V4L2_MPEG_AUDIO_L2_BITRATE_128K;
        case 0x0090: return V4L2_MPEG_AUDIO_L2_BITRATE_160K;
        case 0x00a0: return V4L2_MPEG_AUDIO_L2_BITRATE_192K;
        case 0x00b0: return V4L2_MPEG_AUDIO_L2_BITRATE_224K;
        case 0x00c0: return V4L2_MPEG_AUDIO_L2_BITRATE_256K;
        case 0x00d0: return V4L2_MPEG_AUDIO_L2_BITRATE_320K;
        case 0x00e0: return V4L2_MPEG_AUDIO_L2_BITRATE_384K;
    }
    return V4L2_MPEG_AUDIO_L2_BITRATE_192K;
}

/*****************************************************************************
 * V4L2AudioMode: calculate v4l2 audio mode from pvr-audio-bitmask
 *****************************************************************************/
static uint32_t V4L2AudioMode( uint32_t i_bitmask )
{
    switch( i_bitmask & 0x0300 )
    {
        case 0x0100: return V4L2_MPEG_AUDIO_MODE_JOINT_STEREO;
        case 0x0200: return V4L2_MPEG_AUDIO_MODE_DUAL;
        case 0x0300: return V4L2_MPEG_AUDIO_MODE_MONO;
    }
    return V4L2_MPEG_AUDIO_MODE_STEREO;
}

/*****************************************************************************
 * ConfigureV4L2: set up codec parameters using the new v4l2 api
 *****************************************************************************/
static int ConfigureV4L2( access_t * p_access )
{
    access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
    struct v4l2_ext_controls controls;
    int result;

    memset( &controls, 0, sizeof(struct v4l2_ext_controls) );
    controls.ctrl_class  = V4L2_CTRL_CLASS_MPEG;
    controls.error_idx   = 0;
    controls.reserved[0] = 0;
    controls.reserved[1] = 0;
    controls.count       = 0;
435
436
    controls.controls    = calloc( MAX_V4L2_CTRLS,
                                   sizeof( struct v4l2_ext_control ) );
437

438
    if( controls.controls == NULL )
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
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
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
        return VLC_ENOMEM;

    /* Note: Ignore frame rate.  Doesn't look like it can be changed. */
    if( p_sys->i_bitrate != -1 )
    {
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_VIDEO_BITRATE,
                     p_sys->i_bitrate );
        msg_Dbg( p_access, "Setting [%u] bitrate = %u",
                 controls.count - 1, p_sys->i_bitrate );
    }

    if( p_sys->i_bitrate_peak != -1 )
    {
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
                     p_sys->i_bitrate_peak );
        msg_Dbg( p_access, "Setting [%u] bitrate_peak = %u",
                 controls.count - 1, p_sys->i_bitrate_peak );
    }

    if( p_sys->i_bitrate_mode != -1 )
    {
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
                     p_sys->i_bitrate_mode );
        msg_Dbg( p_access, "Setting [%u] bitrate_mode = %u",
                 controls.count - 1, p_sys->i_bitrate_mode );
    }

    if( p_sys->i_audio_bitmask != -1 )
    {
        /* Sample rate */
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
                    V4L2SampleRate( p_sys->i_audio_bitmask ) );

        /* Encoding layer and bitrate */
        switch( V4L2AudioEncoding( p_sys->i_audio_bitmask ) )
        {
            case V4L2_MPEG_AUDIO_ENCODING_LAYER_1:
                 AddV4L2Ctrl( p_access, &controls,
                              V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
                              V4L2_MPEG_AUDIO_ENCODING_LAYER_1 );
                 AddV4L2Ctrl( p_access, &controls,
                              V4L2_CID_MPEG_AUDIO_L1_BITRATE,
                              V4L2AudioL1Bitrate( p_sys->i_audio_bitmask ) );
                 break;

            case V4L2_MPEG_AUDIO_ENCODING_LAYER_2:
                 AddV4L2Ctrl( p_access, &controls,
                              V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
                              V4L2_MPEG_AUDIO_ENCODING_LAYER_2 );
                 AddV4L2Ctrl( p_access, &controls,
                              V4L2_CID_MPEG_AUDIO_L2_BITRATE,
                              V4L2AudioL2Bitrate( p_sys->i_audio_bitmask ) );
                 break;
        }

        /* Audio mode - stereo or mono */
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_AUDIO_MODE,
                     V4L2AudioMode( p_sys->i_audio_bitmask ) );

        /* See if the user wants any other audio feature */
        if( ( p_sys->i_audio_bitmask & 0x1ff00 ) != 0 )
        {
            /* It would be possible to support the bits that represent:
             *   V4L2_CID_MPEG_AUDIO_MODE_EXTENSION
             *   V4L2_CID_MPEG_AUDIO_EMPHASIS
             *   V4L2_CID_MPEG_AUDIO_CRC
             * but they are not currently used.  Tell the user.
             */
            msg_Err( p_access, "There were bits in pvr-audio-bitmask that were not used.");
        }
        msg_Dbg( p_access, "Setting audio controls");
    }

    if( p_sys->i_keyint != -1 )
    {
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
                     p_sys->i_keyint );
        msg_Dbg( p_access, "Setting [%u] keyint = %u",
                 controls.count - 1, p_sys->i_keyint );
    }

    if( p_sys->i_bframes != -1 )
    {
        AddV4L2Ctrl( p_access, &controls, V4L2_CID_MPEG_VIDEO_B_FRAMES,
                     p_sys->i_bframes );
        msg_Dbg( p_access, "Setting [%u] bframes = %u",
                 controls.count - 1, p_sys->i_bframes );
    }

    result = ioctl( p_sys->i_fd, VIDIOC_S_EXT_CTRLS, &controls );
    if( result < 0 )
    {
        msg_Err( p_access, "Failed to write %u new capture card settings.",
                            controls.error_idx );
    }
534
    free( controls.controls );
535
536
537
538
539
    return VLC_SUCCESS;
}

#endif /* HAVE_NEW_LINUX_VIDEODEV2_H */

540
541
542
543
544
/*****************************************************************************
 * Open: open the device
 *****************************************************************************/
static int Open( vlc_object_t * p_this )
{
545
    access_t *p_access = (access_t*) p_this;
546
    access_sys_t * p_sys;
547
548
549
550
    char * psz_tofree;
    char * psz_parser;
    struct v4l2_capability device_capability;
    int result;
551

552
    memset( &device_capability, 0, sizeof(struct v4l2_capability) );
553

ivoire's avatar
ivoire committed
554
555
556
557
    access_InitFields( p_access );
    ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL );
    p_sys = p_access->p_sys = calloc( 1, sizeof( access_sys_t ));
    if( !p_sys ) return VLC_ENOMEM;
558
559

    /* defaults values */
560
561
    var_Create( p_access, "pvr-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
    p_sys->psz_videodev = var_CreateGetString( p_access, "pvr-device" );
    p_sys->psz_radiodev = var_CreateGetString( p_access, "pvr-radio-device" );
    p_sys->i_standard   = var_CreateGetInteger( p_access, "pvr-norm" );
    p_sys->i_width      = var_CreateGetInteger( p_access, "pvr-width" );
    p_sys->i_height     = var_CreateGetInteger( p_access, "pvr-height" );
    p_sys->i_frequency  = var_CreateGetInteger( p_access, "pvr-frequency" );
    p_sys->i_framerate  = var_CreateGetInteger( p_access, "pvr-framerate" );
    p_sys->i_keyint     = var_CreateGetInteger( p_access, "pvr-keyint" );
    p_sys->i_bframes    = var_CreateGetInteger( p_access, "pvr-bframes" );
    p_sys->i_bitrate    = var_CreateGetInteger( p_access, "pvr-bitrate" );
    p_sys->i_bitrate_peak  = var_CreateGetInteger( p_access, "pvr-bitrate-peak" );
    p_sys->i_bitrate_mode  = var_CreateGetInteger( p_access, "pvr-bitrate-mode" );
    p_sys->i_audio_bitmask = var_CreateGetInteger( p_access, "pvr-audio-bitmask" );
    p_sys->i_volume     = var_CreateGetInteger( p_access, "pvr-audio-volume" );
    p_sys->i_input      = var_CreateGetInteger( p_access, "pvr-channel" );
577

578
    /* parse command line options */
579
    psz_tofree = strdup( p_access->psz_path );
580
    if( !psz_tofree )
581
    {
582
583
        free( p_sys->psz_radiodev );
        free( p_sys->psz_videodev );
584
585
586
        free( p_sys );
        return VLC_ENOMEM;
    }
587

588
    psz_parser = psz_tofree;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
589
    while( *psz_parser )
590
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
591
592
        /* Leading slash -> device path */
        if( *psz_parser == '/' )
593
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
            free( p_sys->psz_videodev );
            p_sys->psz_videodev = strdup( psz_parser );
            break;
        }

        /* Extract option name */
        const char *optname = psz_parser;
        psz_parser = strchr( psz_parser, '=' );
        if( psz_parser == NULL )
            break;
        *psz_parser++ = '\0';

        /* Extract option value */
        char *optval = psz_parser;
        while( memchr( ":,", *psz_parser, 3 /* includes \0 */ ) == NULL )
            psz_parser++;
        if( *psz_parser ) /* more options to come */
            *psz_parser++ = '\0'; /* skip , or : */

        if ( !strcmp( optname, "norm" ) )
        {
            if ( !strcmp( optval, "secam" ) )
                p_sys->i_standard = V4L2_STD_SECAM;
            else if ( !strcmp( optval, "pal" ) )
                p_sys->i_standard = V4L2_STD_PAL;
            else if ( !strcmp( optval, "ntsc" ) )
                p_sys->i_standard = V4L2_STD_NTSC;
621
            else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
                p_sys->i_standard = atoi( optval );
        }
        else if( !strcmp( optname, "channel" ) )
            p_sys->i_input = atoi( optval );
        else if( !strcmp( optname, "device" ) )
        {
            free( p_sys->psz_videodev );
            if( asprintf( &p_sys->psz_videodev, "/dev/video%s", optval ) == -1)
                p_sys->psz_videodev = NULL;
        }
        else if( !strcmp( optname, "frequency" ) )
            p_sys->i_frequency = atoi( optval );
        else if( !strcmp( optname, "framerate" ) )
            p_sys->i_framerate = atoi( optval );
        else if( !strcmp( optname, "keyint" ) )
            p_sys->i_keyint = atoi( optval );
        else if( !strcmp( optname, "bframes" ) )
            p_sys->i_bframes = atoi( optval );
        else if( !strcmp( optname, "width" ) )
            p_sys->i_width = atoi( optval );
        else if( !strcmp( optname, "height" ) )
            p_sys->i_height = atoi( optval );
        else if( !strcmp( optname, "audio" ) )
            p_sys->i_audio_bitmask = atoi( optval );
        else if( !strcmp( optname, "bitrate" ) )
            p_sys->i_bitrate = atoi( optval );
        else if( !strcmp( optname, "maxbitrate" ) )
            p_sys->i_bitrate_peak = atoi( optval );
        else if( !strcmp( optname, "bitratemode" ) )
        {
            if( !strcmp( optval, "vbr" ) )
                p_sys->i_bitrate_mode = 0;
            else if( !strcmp( optval, "cbr" ) )
                p_sys->i_bitrate_mode = 1;
        }
        else if( !strcmp( optname, "size" ) )
        {
            p_sys->i_width = strtol( optval, &optval, 0 );
            p_sys->i_height = atoi( optval );
661
662
        }
    }
663
    free( psz_tofree );
664
665

    /* open the device */
666
    p_sys->i_fd = utf8_open( p_sys->psz_videodev, O_RDWR );
667
    if( p_sys->i_fd < 0 )
668
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
669
670
        msg_Err( p_access, "Cannot open device %s (%m).",
                 p_sys->psz_videodev );
671
        Close( VLC_OBJECT(p_access) );
672
673
        return VLC_EGENERIC;
    }
674
675
676
677
678
    msg_Dbg( p_access, "Using video device: %s.", p_sys->psz_videodev);

    /* See what version of ivtvdriver is running */
    result = ioctl( p_sys->i_fd, VIDIOC_QUERYCAP, &device_capability );
    if( result < 0 )
bigben's avatar
bigben committed
679
    {
680
        msg_Err( p_access, "unknown ivtv/pvr driver version in use" );
681
682
        Close( VLC_OBJECT(p_access) );
        return VLC_EGENERIC;
bigben's avatar
bigben committed
683
    }
684

685
686
687
688
    msg_Dbg( p_access, "%s driver (%s on %s) version %02x.%02x.%02x",
              device_capability.driver,
              device_capability.card,
              device_capability.bus_info,
689
690
691
692
            ( device_capability.version >> 16 ) & 0xff,
            ( device_capability.version >>  8 ) & 0xff,
            ( device_capability.version       ) & 0xff);

693
694
    if ( strncmp( (char *) device_capability.driver, "ivtv", 4 )
           || device_capability.version >= 0x000800 )
695
696
697
    {
        /* Drivers > 0.8.0 use v4l2 API instead of IVTV ioctls */
        msg_Dbg( p_access, "this driver uses the v4l2 API" );
698
        p_sys->b_v4l2_api = true;
699
700
701
    }
    else
    {
702
        p_sys->b_v4l2_api = false;
703
    }
704

705
    /* set the input */
706
707
    if ( p_sys->i_input != -1 )
    {
708
709
710
        result = ioctl( p_sys->i_fd, VIDIOC_S_INPUT, &p_sys->i_input );
        if ( result < 0 )
            msg_Warn( p_access, "Failed to select the requested input pin." );
711
        else
712
            msg_Dbg( p_access, "input set to: %d", p_sys->i_input );
713
714
715
716
717
    }

    /* set the video standard */
    if ( p_sys->i_standard != V4L2_STD_UNKNOWN )
    {
718
719
720
        result = ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard );
        if ( result  < 0 )
            msg_Warn( p_access, "Failed to set the requested video standard." );
721
        else
722
723
            msg_Dbg( p_access, "video standard set to: %x",
                     p_sys->i_standard);
724
725
726
    }

    /* set the picture size */
727
    if ( (p_sys->i_width != -1) || (p_sys->i_height != -1) )
728
    {
729
730
        struct v4l2_format vfmt;

731
        memset( &vfmt, 0, sizeof(struct v4l2_format) );
732
        vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
733
734
735

        result = ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt );
        if ( result < 0 )
736
        {
737
            msg_Warn( p_access, "Failed to read current picture size." );
738
739
740
741
742
743
744
745
746
747
748
749
750
        }
        else
        {
            if ( p_sys->i_width != -1 )
            {
                vfmt.fmt.pix.width = p_sys->i_width;
            }

            if ( p_sys->i_height != -1 )
            {
                vfmt.fmt.pix.height = p_sys->i_height;
            }

751
752
            result = ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt );
            if ( result < 0 )
753
            {
754
                msg_Warn( p_access, "Failed to set requested picture size." );
755
756
757
            }
            else
            {
758
                msg_Dbg( p_access, "picture size set to: %dx%d",
759
760
761
762
763
764
765
                         vfmt.fmt.pix.width, vfmt.fmt.pix.height );
            }
        }
    }

    /* set the frequency */
    if ( p_sys->i_frequency != -1 )
bigben's avatar
bigben committed
766
    {
767
        int i_fd;
768
        struct v4l2_tuner vt;
769

770
771
772
773
774
         /* TODO: let the user choose the tuner */
        memset( &vt, 0, sizeof(struct v4l2_tuner) );

        if ( (p_sys->i_frequency >= pi_radio_range[0])
              && (p_sys->i_frequency <= pi_radio_range[1]) )
775
        {
776
            p_sys->i_radio_fd = utf8_open( p_sys->psz_radiodev, O_RDWR );
777
            if( p_sys->i_radio_fd < 0 )
778
            {
779
                msg_Err( p_access, "Cannot open radio device (%m)." );
780
                Close( VLC_OBJECT(p_access) );
781
782
                return VLC_EGENERIC;
            }
783
784
            msg_Dbg( p_access, "using radio device: %s",
                     p_sys->psz_radiodev );
785
786
787
788
789
790
791
792
            i_fd = p_sys->i_radio_fd;
        }
        else
        {
            i_fd = p_sys->i_fd;
            p_sys->i_radio_fd = -1;
        }

793
794
        result = ioctl( i_fd, VIDIOC_G_TUNER, &vt );
        if ( result < 0 )
bigben's avatar
bigben committed
795
        {
796
            msg_Warn( p_access, "Failed to read tuner information (%m)." );
797
798
799
        }
        else
        {
800
            struct v4l2_frequency vf;
801
802

            memset( &vf, 0, sizeof(struct v4l2_frequency) );
803
            vf.tuner = vt.index;
804

805
806
            result = ioctl( i_fd, VIDIOC_G_FREQUENCY, &vf );
            if ( result < 0 )
807
            {
808
                msg_Warn( p_access, "Failed to read tuner frequency (%m)." );
809
810
811
            }
            else
            {
812
813
814
815
816
                if( vt.capability & V4L2_TUNER_CAP_LOW )
                    vf.frequency = p_sys->i_frequency * 16;
                else
                    vf.frequency = (p_sys->i_frequency * 16 + 500) / 1000;

817
818
                result = ioctl( i_fd, VIDIOC_S_FREQUENCY, &vf );
                if( result < 0 )
819
                {
820
                    msg_Warn( p_access, "Failed to set tuner frequency (%m)." );
821
822
823
824
825
826
                }
                else
                {
                    msg_Dbg( p_access, "tuner frequency set to: %d",
                             p_sys->i_frequency );
                }
827
            }
bigben's avatar
bigben committed
828
829
        }
    }
830

831
832
833
834
835
    /* control parameters */
    if ( p_sys->i_volume != -1 )
    {
        struct v4l2_control ctrl;

836
        memset( &ctrl, 0, sizeof(struct v4l2_control) );
837
838
839
        ctrl.id = V4L2_CID_AUDIO_VOLUME;
        ctrl.value = p_sys->i_volume;

840
841
        result = ioctl( p_sys->i_fd, VIDIOC_S_CTRL, &ctrl );
        if ( result < 0 )
842
        {
843
            msg_Warn( p_access, "Failed to set the volume." );
844
845
846
        }
    }

847
    /* codec parameters */
848
849
850
851
852
853
854
    if ( (p_sys->i_framerate != -1)
            || (p_sys->i_bitrate_mode != -1)
            || (p_sys->i_bitrate_peak != -1)
            || (p_sys->i_keyint != -1)
            || (p_sys->i_bframes != -1)
            || (p_sys->i_bitrate != -1)
            || (p_sys->i_audio_bitmask != -1) )
855
    {
856
        if( p_sys->b_v4l2_api )
857
        {
858
859
#ifdef HAVE_NEW_LINUX_VIDEODEV2_H
            result = ConfigureV4L2( p_access );
860
            if( result != VLC_SUCCESS )
bigben's avatar
bigben committed
861
            {
862
                Close( VLC_OBJECT(p_access) );
863
                return result;
bigben's avatar
bigben committed
864
            }
865
866
867
868
#else
            msg_Warn( p_access, "You have new ivtvdrivers, "
                      "but this vlc was built against an old v4l2 version." );
#endif
bigben's avatar
bigben committed
869
        }
870
871
        else
        {
872
            result = ConfigureIVTV( p_access );
873
            if( result != VLC_SUCCESS )
874
875
876
877
            {
                Close( VLC_OBJECT(p_access) );
                return result;
            }
878
879
        }
    }
880

881
    return VLC_SUCCESS;
882
883
884
885
886
887
888
}

/*****************************************************************************
 * Close: close the device
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
889
    access_t *p_access = (access_t*) p_this;
890
    access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
891

892
893
    if ( p_sys->i_fd != -1 )
        close( p_sys->i_fd );
894
895
    if ( p_sys->i_radio_fd != -1 )
        close( p_sys->i_radio_fd );
ivoire's avatar
ivoire committed
896
897
    free( p_sys->psz_videodev );
    free( p_sys->psz_radiodev );
898
899
900
901
902
903
    free( p_sys );
}

/*****************************************************************************
 * Read
 *****************************************************************************/
904
static ssize_t Read( access_t * p_access, uint8_t * p_buffer, size_t i_len )
905
{
906
    access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
907
    struct pollfd ufd;
908
    int i_ret;
909

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
910
    ufd.fd = p_sys->i_fd;
911
    ufd.events = POLLIN;
912

913
    if( p_access->info.b_eof )
914
915
        return 0;

916
    do
917
    {
918
        if( !vlc_object_alive (p_access) )
919
            return 0;
920
921

        ufd.revents = 0;
922
    }
923
    while( ( i_ret = poll( &ufd, 1, 500 ) ) == 0 );
924
925
926

    if( i_ret < 0 )
    {
927
        msg_Err( p_access, "Polling error (%m)." );
928
929
930
931
        return -1;
    }

    i_ret = read( p_sys->i_fd, p_buffer, i_len );
932
933
    if( i_ret == 0 )
    {
934
        p_access->info.b_eof = true;
935
    }
936
    else if( i_ret > 0 )
937
    {
938
        p_access->info.i_pos += i_ret;
939
940
    }

941
942
943
    return i_ret;
}

944
945
946
947
948
/*****************************************************************************
 * Control
 *****************************************************************************/
static int Control( access_t *p_access, int i_query, va_list args )
{
949
    bool   *pb_bool;
950
951
952
953
954
955
956
    int64_t      *pi_64;

    switch( i_query )
    {
        /* */
        case ACCESS_CAN_SEEK:
        case ACCESS_CAN_FASTSEEK:
957
958
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = false;
959
960
            break;
        case ACCESS_CAN_PAUSE:
961
962
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = false;
963
964
            break;
        case ACCESS_CAN_CONTROL_PACE:
965
966
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = false;
967
968
969
970
971
            break;

        /* */
        case ACCESS_GET_PTS_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
972
            *pi_64 = (int64_t)var_GetInteger( p_access, "pvr-caching" ) * 1000;
973
974
975
976
977
978
979
            break;

        /* */
        case ACCESS_SET_PAUSE_STATE:
            /* Nothing to do */
            break;

980
981
982
        case ACCESS_GET_TITLE_INFO:
        case ACCESS_SET_TITLE:
        case ACCESS_SET_SEEKPOINT:
983
        case ACCESS_SET_PRIVATE_ID_STATE:
984
        case ACCESS_GET_CONTENT_TYPE:
985
986
            return VLC_EGENERIC;

987
        default:
988
            msg_Warn( p_access, "Unimplemented query in control." );
989
990
991
992
993
            return VLC_EGENERIC;

    }
    return VLC_SUCCESS;
}