Commit 02b9cd06 authored by Eric Petit's avatar Eric Petit

Added a special access module for PVR MPEG-2 encoding boards.

 It allows to change the frequency and such things quite easily, from VLC.
 You'll have to --enable-pvr to build it.
parent f46c8fc3
......@@ -1331,6 +1331,16 @@ then
],[])
fi
dnl
dnl special access module for Hauppauge PVR cards
dnl
AC_ARG_ENABLE(pvr,
[ --enable-pvr PVR cards access module (default disabled)])
if test "x${enable_pvr}" = "xyes"
then
PLUGINS="${PLUGINS} pvr"
fi
dnl
dnl VCD module
dnl
......
......@@ -7,6 +7,7 @@ EXTRA_DIST = \
access/dvdplay/Modules.am \
access/dvdread/Modules.am \
access/mms/Modules.am \
access/pvr/Modules.am \
access/satellite/Modules.am \
access/v4l/Modules.am \
access/vcd/Modules.am \
......
SOURCES_pvr = modules/access/pvr/pvr.c \
modules/access/pvr/videodev2.h
/*****************************************************************************
* pvr.c
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: pvr.c,v 1.1 2003/06/04 21:41:47 titer Exp $
*
* Authors: Eric Petit <titer@videolan.org>
*
* 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
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include "videodev2.h"
/* 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 {
uint32_t aspect;
uint32_t audio;
uint32_t bframes;
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;
};
/*****************************************************************************
* Prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static ssize_t Read ( input_thread_t *, byte_t *, size_t );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("Hauppauge PVR cards input") );
set_capability( "access", 0 );
add_shortcut( "pvr" );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* Private access data
*****************************************************************************/
struct access_sys_t
{
/* file descriptor */
int i_fd;
/* options */
int i_device;
int i_standard;
int i_width;
int i_height;
int i_frequency;
int i_framerate;
int i_bitrate;
int i_bitrate_peak;
};
/*****************************************************************************
* Open: open the device
*****************************************************************************/
static int Open( vlc_object_t * p_this )
{
input_thread_t * p_input = (input_thread_t*) p_this;
access_sys_t * p_sys;
char * psz_tofree, * psz_parser, * psz_device;
struct v4l2_format vfmt;
struct v4l2_frequency vf;
struct ivtv_ioctl_codec codec;
p_input->pf_read = Read;
p_input->stream.b_pace_control = 0;
p_input->stream.b_seekable = 0;
p_input->i_pts_delay = 1000000;
/* create private access data */
p_sys = calloc( sizeof( access_sys_t ), 1 );
p_input->p_access_data = p_sys;
/* defaults values */
p_sys->i_device = 0;
p_sys->i_standard = V4L2_STD_SECAM;
p_sys->i_width = 720;
p_sys->i_height = 576;
p_sys->i_frequency = 567250; /* M6 ;) */
p_sys->i_framerate = 25;
p_sys->i_bitrate = 3000000;
p_sys->i_bitrate_peak = 4000000;
/* parse command line options */
/* TODO : _really_ parse all options ;) */
psz_tofree = strdup( p_input->psz_name );
psz_parser = psz_tofree;
if( *psz_parser )
{
for( ;; )
{
if( !strncmp( psz_parser, "device=", strlen( "device" ) ) )
{
p_sys->i_device = strtol( psz_parser + strlen( "device" ),
&psz_parser, 0 );
}
else if( !strncmp( psz_parser, "frequency=",
strlen( "frequency=" ) ) )
{
p_sys->i_frequency =
strtol( psz_parser + strlen( "frequency=" ),
&psz_parser, 0 );
}
if( *psz_parser )
psz_parser++;
else
break;
}
}
free( psz_tofree );
msg_Dbg( p_input, "device: /dev/video%d, standard: %x, size: %dx%d, "
"framerate: %d, frequency: %d, bitrate: %d/%d",
p_sys->i_device, p_sys->i_standard, p_sys->i_width,
p_sys->i_height, p_sys->i_frequency, p_sys->i_framerate,
p_sys->i_bitrate, p_sys->i_bitrate_peak );
/* open the device */
psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
sprintf( psz_device, "/dev/video%d", p_sys->i_device );
if( ( p_sys->i_fd = open( psz_device, O_RDWR ) ) < 0 )
{
msg_Err( p_input, "cannot open device (%s)", strerror( errno ) );
return VLC_EGENERIC;
}
free( psz_device );
/* set the video standard */
if( ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard ) < 0 )
{
msg_Warn( p_input, "VIDIOC_S_STD failed" );
}
/* set the picture size */
if( ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt ) < 0 )
{
msg_Warn( p_input, "VIDIOC_G_FMT failed" );
}
else
{
vfmt.fmt.pix.width = p_sys->i_width;
vfmt.fmt.pix.height = p_sys->i_height;
if( ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt ) < 0 )
{
msg_Warn( p_input, "VIDIOC_S_FMT failed" );
}
}
/* set the frequency */
vf.tuner = 0; /* TODO: let the user choose the tuner */
if( ioctl( p_sys->i_fd, VIDIOC_G_FREQUENCY, &vf ) < 0 )
{
msg_Warn( p_input, "VIDIOC_G_FREQUENCY failed (%s)",
strerror( errno ) );
}
else
{
vf.frequency = p_sys->i_frequency * 16 / 1000;
if( ioctl( p_sys->i_fd, VIDIOC_S_FREQUENCY, &vf ) < 0 )
{
msg_Warn( p_input, "VIDIOC_S_FREQUENCY failed (%s)",
strerror( errno ) );
}
}
/* codec parameters */
if( ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec ) < 0 )
{
msg_Warn( p_input, "IVTV_IOC_G_CODEC failed" );
}
else
{
switch( p_sys->i_framerate )
{
case 30:
codec.framerate = 0;
break;
case 25:
codec.framerate = 1;
break;
default:
msg_Warn( p_input, "invalid framerate, reverting to 25" );
codec.framerate = 1;
break;
}
codec.bitrate = p_sys->i_bitrate;
codec.bitrate_peak = p_sys->i_bitrate_peak;
if( ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec ) < 0 )
{
msg_Warn( p_input, "IVTV_IOC_S_CODEC failed" );
}
}
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: close the device
*****************************************************************************/
static void Close( vlc_object_t * p_this )
{
input_thread_t * p_input = (input_thread_t*) p_this;
access_sys_t * p_sys = p_input->p_access_data;
close( p_sys->i_fd );
free( p_sys );
}
/*****************************************************************************
* Read
*****************************************************************************/
static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
access_sys_t * p_sys = p_input->p_access_data;
int i_ret;
struct timeval timeout;
fd_set fds;
FD_ZERO( &fds );
FD_SET( p_sys->i_fd, &fds );
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
while( !( i_ret = select( p_sys->i_fd + 1, &fds,
NULL, NULL, &timeout ) ) )
{
FD_ZERO( &fds );
FD_SET( p_sys->i_fd, &fds );
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
if( p_input->b_die || p_input->b_error )
return 0;
}
if( i_ret < 0 )
{
msg_Err( p_input, "select error (%s)", strerror( errno ) );
return -1;
}
i_ret = read( p_sys->i_fd, p_buffer, i_len );
return i_ret;
}
#ifndef __LINUX_VIDEODEV2_H
#define __LINUX_VIDEODEV2_H
/*
* Video for Linux Two
*
* Header file for v4l or V4L2 drivers and applications, for
* Linux kernels 2.2.x or 2.4.x.
*
* See http://bytesex.org/v4l/ for API specs and other
* v4l2 documentation.
*
* Author: Bill Dirks <bdirks@pacbell.net>
* Justin Schoeman
* et al.
*/
/*
* M I S C E L L A N E O U S
*/
/* Four-character-code (FOURCC) */
#define v4l2_fourcc(a,b,c,d)\
(((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
/*
* E N U M S
*/
enum v4l2_field {
V4L2_FIELD_ANY = 0, /* driver can choose from none,
top, bottom, interlaced
depending on whatever it thinks
is approximate ... */
V4L2_FIELD_NONE = 1, /* this device has no fields ... */
V4L2_FIELD_TOP = 2, /* top field only */
V4L2_FIELD_BOTTOM = 3, /* bottom field only */
V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */
V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one
buffer, top-bottom order */
V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */
V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into
separate buffers */
};
#define V4L2_FIELD_HAS_TOP(field) \
((field) == V4L2_FIELD_TOP ||\
(field) == V4L2_FIELD_INTERLACED ||\
(field) == V4L2_FIELD_SEQ_TB ||\
(field) == V4L2_FIELD_SEQ_BT)
#define V4L2_FIELD_HAS_BOTTOM(field) \
((field) == V4L2_FIELD_BOTTOM ||\
(field) == V4L2_FIELD_INTERLACED ||\
(field) == V4L2_FIELD_SEQ_TB ||\
(field) == V4L2_FIELD_SEQ_BT)
#define V4L2_FIELD_HAS_BOTH(field) \
((field) == V4L2_FIELD_INTERLACED ||\
(field) == V4L2_FIELD_SEQ_TB ||\
(field) == V4L2_FIELD_SEQ_BT)
enum v4l2_buf_type {
V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
V4L2_BUF_TYPE_VBI_CAPTURE = 4,
V4L2_BUF_TYPE_VBI_OUTPUT = 5,
V4L2_BUF_TYPE_PRIVATE = 0x80,
};
enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_INTEGER = 1,
V4L2_CTRL_TYPE_BOOLEAN = 2,
V4L2_CTRL_TYPE_MENU = 3,
V4L2_CTRL_TYPE_BUTTON = 4,
};
enum v4l2_tuner_type {
V4L2_TUNER_RADIO = 1,
V4L2_TUNER_ANALOG_TV = 2,
};
enum v4l2_memory {
V4L2_MEMORY_MMAP = 1,
V4L2_MEMORY_USERPTR = 2,
V4L2_MEMORY_OVERLAY = 3,
};
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
enum v4l2_colorspace {
/* ITU-R 601 -- broadcast NTSC/PAL */
V4L2_COLORSPACE_SMPTE170M = 1,
/* 1125-Line (US) HDTV */
V4L2_COLORSPACE_SMPTE240M = 2,
/* HD and modern captures. */
V4L2_COLORSPACE_REC709 = 3,
/* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
V4L2_COLORSPACE_BT878 = 4,
/* These should be useful. Assume 601 extents. */
V4L2_COLORSPACE_470_SYSTEM_M = 5,
V4L2_COLORSPACE_470_SYSTEM_BG = 6,
/* I know there will be cameras that send this. So, this is
* unspecified chromaticities and full 0-255 on each of the
* Y'CbCr components
*/
V4L2_COLORSPACE_JPEG = 7,
/* For RGB colourspaces, this is probably a good start. */
V4L2_COLORSPACE_SRGB = 8,
};
struct v4l2_rect {
__s32 left;
__s32 top;
__s32 width;
__s32 height;
};
struct v4l2_fract {
__u32 numerator;
__u32 denominator;
};
/*
* D R I V E R C A P A B I L I T I E S
*/
struct v4l2_capability
{
__u8 driver[16]; /* i.e. "bttv" */
__u8 card[32]; /* i.e. "Hauppauge WinTV" */
__u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */
__u32 version; /* should use KERNEL_VERSION() */
__u32 capabilities; /* Device capabilities */
__u32 reserved[4];
};
/* Values for 'capabilities' field */
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */
#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */
#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */
#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */
#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */
#define V4L2_CAP_TUNER 0x00010000 /* Has a tuner */
#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */
#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */
#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */
#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */
/*
* V I D E O I M A G E F O R M A T
*/
struct v4l2_pix_format
{
__u32 width;
__u32 height;
__u32 pixelformat;
enum v4l2_field field;
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
enum v4l2_colorspace colorspace;
__u32 priv; /* private data, depends on pixelformat */
};
/* Pixel format FOURCC depth Description */
#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */
#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */
#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */
#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */
#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */
#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */
#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */
#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */
/* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */
/* The following formats are not defined in the V4L2 specification */
#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */
/* compressed formats */
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */
#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */
#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */
/*
* F O R M A T E N U M E R A T I O N
*/
struct v4l2_fmtdesc
{
__u32 index; /* Format number */
enum v4l2_buf_type type; /* buffer type */
__u32 flags;
__u8 description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
__u32 reserved[4];
};
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
/*
* T I M E C O D E
*/
struct v4l2_timecode
{
__u32 type;
__u32 flags;
__u8 frames;
__u8 seconds;
__u8 minutes;
__u8 hours;
__u8 userbits[4];
};
/* Type */
#define V4L2_TC_TYPE_24FPS 1
#define V4L2_TC_TYPE_25FPS 2
#define V4L2_TC_TYPE_30FPS 3
#define V4L2_TC_TYPE_50FPS 4
#define V4L2_TC_TYPE_60FPS 5
/* Flags */
#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */
#define V4L2_TC_FLAG_COLORFRAME 0x0002
#define V4L2_TC_USERBITS_field 0x000C
#define V4L2_TC_USERBITS_USERDEFINED 0x0000
#define V4L2_TC_USERBITS_8BITCHARS 0x0008
/* The above is based on SMPTE timecodes */
/*
* C O M P R E S S I O N P A R A M E T E R S
*/
#if 0
/* ### generic compression settings don't work, there is too much
* ### codec-specific stuff. Maybe reuse that for MPEG codec settings
* ### later ... */
struct v4l2_compression
{
__u32 quality;
__u32 keyframerate;
__u32 pframerate;
__u32 reserved[5];
};
#endif
struct v4l2_jpegcompression
{
int quality;
int APPn; /* Number of APP segment to be written,
* must be 0..15 */
int APP_len; /* Length of data in JPEG APPn segment */
char APP_data[60]; /* Data in the JPEG APPn segment. */
int COM_len; /* Length of data in JPEG COM segment */
char COM_data[60]; /* Data in JPEG COM segment */
__u32 jpeg_markers; /* Which markers should go into the JPEG
* output. Unless you exactly know what
* you do, leave them untouched.
* Inluding less markers will make the
* resulting code smaller, but there will
* be fewer aplications which can read it.
* The presence of the APP and COM marker
* is influenced by APP_len and COM_len
* ONLY, not by this property! */
#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */
#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will
* allways use APP0 */
};
/*
* M E M O R Y - M A P P I N G B U F F E R S
*/
struct v4l2_requestbuffers
{
__u32 count;
enum v4l2_buf_type type;
enum v4l2_memory memory;
__u32 reserved[2];
};
struct v4l2_buffer
{
__u32 index;
enum v4l2_buf_type type;
__u32 bytesused;
__u32 flags;
enum v4l2_field field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
enum v4l2_memory memory;
union {
__u32 offset;
unsigned long userptr;
} m;
__u32 length;
__u32 reserved[2];