changeset 18997:73b8f5ff772d

added new pvr:// input for ivtv based cards
author ben
date Mon, 10 Jul 2006 21:32:19 +0000
parents 49f158e94fce
children 712dd0de8641
files cfg-common.h configure libmpdemux/Makefile libmpdemux/stream.c libmpdemux/stream.h libmpdemux/stream_pvr.c
diffstat 6 files changed, 1099 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/cfg-common.h	Mon Jul 10 18:36:50 2006 +0000
+++ b/cfg-common.h	Mon Jul 10 21:32:19 2006 +0000
@@ -135,6 +135,11 @@
 #else
 	{"tv", "MPlayer was compiled without TV interface support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
 #endif
+#ifdef HAVE_PVR
+	{"pvr", pvropts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+#else
+	{"pvr", "MPlayer was compiled without V4L2/PVR interface support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
+#endif
 	{"vivo", vivoopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 #ifdef HAS_DVBIN_SUPPORT
 	{"dvbin", dvbin_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
@@ -418,6 +423,31 @@
 };
 #endif
 
+#ifdef HAVE_PVR
+extern int pvr_param_aspect_ratio;
+extern int pvr_param_sample_rate;
+extern int pvr_param_audio_layer;
+extern int pvr_param_audio_bitrate;
+extern char *pvr_param_audio_mode;
+extern int pvr_param_bitrate;
+extern char *pvr_param_bitrate_mode;
+extern int pvr_param_bitrate_peak;
+extern char *pvr_param_stream_type;
+
+m_option_t pvropts_conf[]={
+	{"aspect", &pvr_param_aspect_ratio, CONF_TYPE_INT, 0, 1, 4, NULL},
+	{"arate", &pvr_param_sample_rate, CONF_TYPE_INT, 0, 32000, 48000, NULL},
+	{"alayer", &pvr_param_audio_layer, CONF_TYPE_INT, 0, 1, 2, NULL},
+	{"abitrate", &pvr_param_audio_bitrate, CONF_TYPE_INT, 0, 32, 448, NULL},
+	{"amode", &pvr_param_audio_mode, CONF_TYPE_STRING, 0, 0, 0, NULL},
+	{"vbitrate", &pvr_param_bitrate, CONF_TYPE_INT, 0, 0, 0, NULL},
+	{"vmode", &pvr_param_bitrate_mode, CONF_TYPE_STRING, 0, 0, 0, NULL},
+	{"vpeak", &pvr_param_bitrate_peak, CONF_TYPE_INT, 0, 0, 0, NULL},
+	{"fmt", &pvr_param_stream_type, CONF_TYPE_STRING, 0, 0, 0, NULL},
+	{NULL, NULL, 0, 0, 0, 0, NULL}
+};
+#endif
+
 #ifdef HAS_DVBIN_SUPPORT
 #include "libmpdemux/dvbin.h"
 extern m_config_t dvbin_opts_conf[];
--- a/configure	Mon Jul 10 18:36:50 2006 +0000
+++ b/configure	Mon Jul 10 21:32:19 2006 +0000
@@ -221,6 +221,7 @@
   --disable-tv-v4l       disable Video4Linux TV Interface support [autodetect]
   --disable-tv-v4l2      disable Video4Linux2 TV Interface support [autodetect]
   --disable-tv-bsdbt848  disable BSD BT848 Interface support [autodetect]
+  --disable-pvr          disable Video4Linux2/IVTV PVR support [autodetect]
   --disable-rtc          disable RTC (/dev/rtc) on Linux [autodetect]
   --disable-network      disable network support (for: http/mms/rtp) [enable]
   --enable-winsock2      enable winsock2 usage [autodetect]
@@ -1642,6 +1643,7 @@
 _tv_v4l=auto
 _tv_v4l2=auto
 _tv_bsdbt848=auto
+_pvr=auto
 _network=yes
 _winsock2=auto
 _smbsupport=auto
@@ -1877,6 +1879,8 @@
   --disable-tv-v4l)	_tv_v4l=no	;;
   --enable-tv-v4l2)	_tv_v4l2=yes	;;
   --disable-tv-v4l2)	_tv_v4l2=no	;;
+  --enable-pvr)  	_pvr=yes	;;
+  --disable-pvr)	_pvr=no 	;;
   --enable-fastmemcpy)	_fastmemcpy=yes	;;
   --disable-fastmemcpy)	_fastmemcpy=no	;;
   --enable-network)	_network=yes	;;
@@ -6802,6 +6806,31 @@
 echores "$_tv_v4l2"
 
 
+echocheck "Video 4 Linux 2/IVTV PVR interface"
+if test "$_pvr" = auto ; then
+ _pvr=no
+ if test "$_tv_v4l2" = yes && linux ; then
+  cat > $TMPC <<EOF
+#include <stdlib.h>
+#include <inttypes.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/ivtv.h>
+int main(void) { return 0; }
+EOF
+  cc_check && _pvr=yes
+ fi
+fi
+if test "$_pvr" = yes ; then
+  _def_pvr='#define HAVE_PVR 1'
+  _inputmodules="pvr $_inputmodules"
+else
+  _noinputmodules="pvr $_noinputmodules"
+  _def_pvr='#undef HAVE_PVR'
+fi
+echores "$_pvr"
+
+
 echocheck "audio select()"
 if test "$_select" = no ; then
   _def_select='#undef HAVE_AUDIO_SELECT'
@@ -7507,6 +7536,7 @@
 TV_V4L = $_tv_v4l
 TV_V4L2 = $_tv_v4l2
 TV_BSDBT848 = $_tv_bsdbt848
+PVR = $_pvr
 VCD = $_vcd
 HAVE_DVD = $_have_dvd
 DVDREAD = $_dvdread
@@ -8047,6 +8077,9 @@
 /* Enable *BSD BrookTree TV interface support */
 $_def_tv_bsdbt848
 
+/* Enable Video 4 Linux 2/IVTV PVR support */
+$_def_pvr
+
 /* Define if your processor stores words with the most significant
    byte first (like Motorola and SPARC, unlike Intel and VAX).  */
 $_def_words_endian
--- a/libmpdemux/Makefile	Mon Jul 10 18:36:50 2006 +0000
+++ b/libmpdemux/Makefile	Mon Jul 10 21:32:19 2006 +0000
@@ -74,6 +74,9 @@
   endif
   ifeq ($(TV_V4L2),yes)
   SRCS += tvi_v4l2.c audio_in.c
+    ifeq ($(PVR),yes)
+    SRCS += stream_pvr.c
+    endif
   endif
   ifeq ($(TV_V4L),yes)
   SRCS += tvi_v4l.c audio_in.c
--- a/libmpdemux/stream.c	Mon Jul 10 18:36:50 2006 +0000
+++ b/libmpdemux/stream.c	Mon Jul 10 21:32:19 2006 +0000
@@ -54,6 +54,9 @@
 #ifdef HAS_DVBIN_SUPPORT
 extern stream_info_t stream_info_dvb;
 #endif
+#ifdef HAVE_PVR
+extern stream_info_t stream_info_pvr;
+#endif
 #ifdef HAVE_FTP
 extern stream_info_t stream_info_ftp;
 #endif
@@ -101,6 +104,9 @@
 #ifdef HAS_DVBIN_SUPPORT
   &stream_info_dvb,
 #endif
+#ifdef HAVE_PVR
+  &stream_info_pvr,
+#endif
 #ifdef HAVE_FTP
   &stream_info_ftp,
 #endif
--- a/libmpdemux/stream.h	Mon Jul 10 18:36:50 2006 +0000
+++ b/libmpdemux/stream.h	Mon Jul 10 21:32:19 2006 +0000
@@ -21,6 +21,7 @@
 #define STREAMTYPE_DVB 13
 #define STREAMTYPE_VSTREAM 14
 #define STREAMTYPE_SDP 15
+#define STREAMTYPE_PVR 16
 
 #define STREAM_BUFFER_SIZE 2048
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/stream_pvr.c	Mon Jul 10 21:32:19 2006 +0000
@@ -0,0 +1,1026 @@
+/*
+ *  Copyright (C) 2006 Benjamin Zores
+ *   Stream layer for WinTV PVR-150/250/350 (a.k.a IVTV) PVR cards.
+ *   See http://ivtvdriver.org/index.php/Main_Page for more details on the
+ *    cards supported by the ivtv driver.
+ *
+ *   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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <inttypes.h>
+#include <sys/poll.h>
+#include <linux/videodev2.h>
+#include <linux/ivtv.h>
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "tv.h"
+
+#define PVR_DEFAULT_DEVICE "/dev/video0"
+
+/* logging mechanisms */
+#define LOG_LEVEL_PVR  "[pvr]"
+#define LOG_LEVEL_V4L2 "[v4l2]"
+#define LOG_LEVEL_IVTV "[ivtv]"
+
+/* IVTV driver settings (see http://ivtvdriver.org/index.php/Ivtvctl ) */
+
+/* codec aspect ratio (1:1, 4:3, 16:9, 2.21:1) */
+#define PVR_ASPECT_RATIO_1_1                                   1
+#define PVR_ASPECT_RATIO_4_3                                   2
+#define PVR_ASPECT_RATIO_16_9                                  3
+#define PVR_ASPECT_RATIO_2_21_1                                4
+
+/* audio codec sample rate (32KHz, CD 44.1 KHz, AC97 48 KHz) */
+#define PVR_AUDIO_SAMPLE_RATE_44_1_KHZ                         0x0000
+#define PVR_AUDIO_SAMPLE_RATE_48_KHZ                           0x0001
+#define PVR_AUDIO_SAMPLE_RATE_32_KHZ                           0x0002
+
+/* audio codec layer (1 or 2) */
+#define PVR_AUDIO_LAYER_1                                      0x0004
+#define PVR_AUDIO_LAYER_2                                      0x0008
+
+/* audio codec bitrate */
+#define PVR_AUDIO_BITRATE_32                                   0x0010
+#define PVR_AUDIO_BITRATE_L1_64                                0x0020
+#define PVR_AUDIO_BITRATE_L1_96                                0x0030
+#define PVR_AUDIO_BITRATE_L1_128                               0x0040
+#define PVR_AUDIO_BITRATE_L1_160                               0x0050
+#define PVR_AUDIO_BITRATE_L1_192                               0x0060
+#define PVR_AUDIO_BITRATE_L1_224                               0x0070
+#define PVR_AUDIO_BITRATE_L1_256                               0x0080
+#define PVR_AUDIO_BITRATE_L1_288                               0x0090
+#define PVR_AUDIO_BITRATE_L1_320                               0x00A0
+#define PVR_AUDIO_BITRATE_L1_352                               0x00B0
+#define PVR_AUDIO_BITRATE_L1_384                               0x00C0
+#define PVR_AUDIO_BITRATE_L1_416                               0x00D0
+#define PVR_AUDIO_BITRATE_L1_448                               0x00E0
+#define PVR_AUDIO_BITRATE_L2_48                                0x0020
+#define PVR_AUDIO_BITRATE_L2_56                                0x0030
+#define PVR_AUDIO_BITRATE_L2_64                                0x0040
+#define PVR_AUDIO_BITRATE_L2_80                                0x0050
+#define PVR_AUDIO_BITRATE_L2_96                                0x0060
+#define PVR_AUDIO_BITRATE_L2_112                               0x0070
+#define PVR_AUDIO_BITRATE_L2_128                               0x0080
+#define PVR_AUDIO_BITRATE_L2_160                               0x0090
+#define PVR_AUDIO_BITRATE_L2_192                               0x00A0
+#define PVR_AUDIO_BITRATE_L2_224                               0x00B0
+#define PVR_AUDIO_BITRATE_L2_256                               0x00C0
+#define PVR_AUDIO_BITRATE_L2_320                               0x00D0
+#define PVR_AUDIO_BITRATE_L2_384                               0x00E0
+
+/* audio codec mode */
+#define PVR_AUDIO_MODE_ARG_STEREO                              "stereo"
+#define PVR_AUDIO_MODE_ARG_JOINT_STEREO                        "joint_stereo"
+#define PVR_AUDIO_MODE_ARG_DUAL                                "dual"
+#define PVR_AUDIO_MODE_ARG_MONO                                "mono"
+#define PVR_AUDIO_MODE_STEREO                                  0x0000
+#define PVR_AUDIO_MODE_JOINT_STEREO                            0x0100
+#define PVR_AUDIO_MODE_DUAL                                    0x0200
+#define PVR_AUDIO_MODE_MONO                                    0x0300
+
+/* video codec bitrate mode */
+#define PVR_VIDEO_BITRATE_MODE_ARG_VBR                         "vbr"
+#define PVR_VIDEO_BITRATE_MODE_ARG_CBR                         "cbr"
+#define PVR_VIDEO_BITRATE_MODE_VBR                             0
+#define PVR_VIDEO_BITRATE_MODE_CBR                             1
+
+/* video codec stream type */
+#define PVR_VIDEO_STREAM_TYPE_PS                               "ps"
+#define PVR_VIDEO_STREAM_TYPE_TS                               "ts"
+#define PVR_VIDEO_STREAM_TYPE_MPEG1                            "mpeg1"
+#define PVR_VIDEO_STREAM_TYPE_DVD                              "dvd"
+#define PVR_VIDEO_STREAM_TYPE_VCD                              "vcd"
+#define PVR_VIDEO_STREAM_TYPE_SVCD                             "svcd"
+#define PVR_VIDEO_STREAM_TYPE_DVD_S1                           "dvds1"
+#define PVR_VIDEO_STREAM_TYPE_DVD_S2                           "dvds2"
+
+/* command line arguments */
+int pvr_param_aspect_ratio = 0;
+int pvr_param_sample_rate = 0;
+int pvr_param_audio_layer = 0;
+int pvr_param_audio_bitrate = 0;
+char *pvr_param_audio_mode = NULL;
+int pvr_param_bitrate = 0;
+char *pvr_param_bitrate_mode = NULL;
+int pvr_param_bitrate_peak = 0;
+char *pvr_param_stream_type = NULL;
+
+struct pvr_t {
+  int dev_fd;
+  char *video_dev;
+
+  /* v4l2 params */
+  int mute;
+  int input;
+  int normid;
+  int brightness;
+  int contrast;
+  int hue;
+  int saturation;
+  int width;
+  int height;
+  char *freq;
+
+  /* ivtv params */
+  int aspect;
+  int samplerate;
+  int layer;
+  int audio_rate;
+  int audio_mode;
+  int bitrate;
+  int bitrate_mode;
+  int bitrate_peak;
+  int stream_type;
+};
+
+static struct pvr_t *
+pvr_init (void)
+{
+  struct pvr_t *pvr = NULL;
+
+  pvr = malloc (sizeof (struct pvr_t)); 
+  pvr->dev_fd = -1;
+  pvr->video_dev = strdup (PVR_DEFAULT_DEVICE);
+
+  /* v4l2 params */
+  pvr->mute = 0;
+  pvr->input = 0;
+  pvr->normid = -1;
+  pvr->brightness = 0;
+  pvr->contrast = 0;
+  pvr->hue = 0;
+  pvr->saturation = 0;
+  pvr->width = -1;
+  pvr->height = -1;
+  pvr->freq = NULL;
+
+  /* ivtv params */
+  pvr->aspect = -1;
+  pvr->samplerate = -1;
+  pvr->layer = -1;
+  pvr->audio_rate = -1;
+  pvr->audio_mode = -1;
+  pvr->bitrate = -1;
+  pvr->bitrate_mode = -1;
+  pvr->bitrate_peak = -1;
+  pvr->stream_type = -1;
+  
+  return pvr;
+}
+
+static void
+pvr_uninit (struct pvr_t *pvr)
+{
+  if (!pvr)
+    return;
+
+  /* close device */
+  if (pvr->dev_fd)
+    close (pvr->dev_fd);
+  
+  if (pvr->video_dev)
+    free (pvr->video_dev);
+  if (pvr->freq)
+    free (pvr->freq);
+  free (pvr);
+}
+
+/* IVTV layer */
+
+static void
+parse_ivtv_options (struct pvr_t *pvr)
+{
+  if (!pvr)
+    return;
+
+  /* -pvr aspect=digit */
+  if (pvr_param_aspect_ratio >= 1 && pvr_param_aspect_ratio <= 4)
+    pvr->aspect = pvr_param_aspect_ratio;
+
+  /* -pvr arate=x */
+  if (pvr_param_sample_rate != 0)
+  {
+    switch (pvr_param_sample_rate)
+    {
+    case 32000:
+      pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_32_KHZ;
+      break;
+    case 44100:
+      pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_44_1_KHZ;
+      break;
+    case 48000:
+      pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_48_KHZ;
+      break;
+    default:
+      break;
+    }
+  }
+
+  /* -pvr alayer=x */
+  if (pvr_param_audio_layer == 1)
+    pvr->layer = PVR_AUDIO_LAYER_1;
+  else if (pvr_param_audio_layer == 2)
+    pvr->layer = PVR_AUDIO_LAYER_2;
+
+  /* -pvr abitrate=x */
+  if (pvr_param_audio_bitrate != 0)
+  {
+    /* set according to layer or use layer 1 by default if not specified */
+    switch (pvr_param_audio_bitrate)
+    {
+    case 32:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_32;
+      break;
+    case 48:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L2_48;
+      break;
+    case 56:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L2_56;
+      break;
+    case 64:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_64 : PVR_AUDIO_BITRATE_L1_64;
+      break;
+    case 80:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L2_80;
+      break;
+    case 96:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_96 : PVR_AUDIO_BITRATE_L1_96;
+      break;
+    case 112:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L2_112;
+      break;
+    case 128:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_128 : PVR_AUDIO_BITRATE_L1_128;
+      break;
+    case 160:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_160 : PVR_AUDIO_BITRATE_L1_160;
+      break;
+    case 192:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_192 : PVR_AUDIO_BITRATE_L1_192;
+      break;
+    case 224:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_224 : PVR_AUDIO_BITRATE_L1_224;
+      break;
+    case 256:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_256 : PVR_AUDIO_BITRATE_L1_256;
+      break;
+    case 288:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L1_288;
+      break;
+    case 320:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_320 : PVR_AUDIO_BITRATE_L1_320;
+      break;
+    case 352:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L1_352;
+      break;
+    case 384:
+      pvr->audio_rate = (pvr_param_audio_layer == 2) ?
+        PVR_AUDIO_BITRATE_L2_384 : PVR_AUDIO_BITRATE_L1_384;
+      break;
+    case 416:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L1_416;
+      break;
+    case 448:
+      pvr->audio_rate = PVR_AUDIO_BITRATE_L1_448;
+      break;
+    default:
+      break;
+    }
+  }
+  
+  /* -pvr amode=x */
+  if (pvr_param_audio_mode)
+  {
+    if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_STEREO))
+      pvr->audio_mode = PVR_AUDIO_MODE_STEREO;
+    else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_JOINT_STEREO))
+      pvr->audio_mode = PVR_AUDIO_MODE_JOINT_STEREO;
+    else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_DUAL))
+      pvr->audio_mode = PVR_AUDIO_MODE_DUAL;
+    else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_MONO))
+      pvr->audio_mode = PVR_AUDIO_MODE_MONO;
+    else /* for anything else, set to stereo */
+      pvr->audio_mode = PVR_AUDIO_MODE_STEREO;
+  }
+
+  /* -pvr vbitrate=x */
+  if (pvr_param_bitrate)
+    pvr->bitrate = pvr_param_bitrate;
+
+  /* -pvr vmode=x */
+  if (pvr_param_bitrate_mode)
+  {
+    if (!strcmp (pvr_param_bitrate_mode, PVR_VIDEO_BITRATE_MODE_ARG_VBR))
+      pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR;
+    else if (!strcmp (pvr_param_bitrate_mode, PVR_VIDEO_BITRATE_MODE_ARG_CBR))
+      pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_CBR;
+    else /* for anything else, set to VBR */
+      pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR;
+  }
+
+  /* -pvr vpeak=x */
+  if (pvr_param_bitrate_peak)
+    pvr->bitrate_peak = pvr_param_bitrate_peak;
+
+  /* -pvr fmt=x */
+  if (pvr_param_stream_type)
+  {
+    if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_PS))
+      pvr->stream_type = IVTV_STREAM_PS;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_TS))
+      pvr->stream_type = IVTV_STREAM_TS;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_MPEG1))
+      pvr->stream_type = IVTV_STREAM_MPEG1;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD))
+      pvr->stream_type = IVTV_STREAM_DVD;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_VCD))
+      pvr->stream_type = IVTV_STREAM_VCD;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_SVCD))
+      pvr->stream_type = IVTV_STREAM_SVCD;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD_S1))
+      pvr->stream_type = IVTV_STREAM_DVD_S1;
+    else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD_S2))
+      pvr->stream_type = IVTV_STREAM_DVD_S2;
+    else /* for anything else, set to MPEG PS */
+      pvr->stream_type = IVTV_STREAM_PS;
+  }
+}
+
+static int
+set_ivtv_settings (struct pvr_t *pvr)
+{
+  struct ivtv_ioctl_codec codec;
+
+  if (!pvr)
+    return -1;
+  
+  if (pvr->dev_fd < 0)
+    return -1;
+
+  /* get current settings */
+  if (ioctl (pvr->dev_fd, IVTV_IOC_G_CODEC, &codec) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't get codec (%s).\n", LOG_LEVEL_IVTV, strerror (errno));
+    return -1;
+  }
+  
+  /* set default encoding settings
+   * may be overlapped by user parameters
+   * Use VBR MPEG_PS encoding at 6 Mbps (peak at 9.6 Mbps)
+   * with 48 KHz L2 384 kbps audio.
+   */
+  codec.aspect = PVR_ASPECT_RATIO_4_3;
+  codec.bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR;
+  codec.bitrate = 6000000;
+  codec.bitrate_peak = 9600000;
+  codec.stream_type = IVTV_STREAM_PS;
+  codec.audio_bitmask = PVR_AUDIO_LAYER_2
+    | PVR_AUDIO_BITRATE_L2_384 | PVR_AUDIO_SAMPLE_RATE_48_KHZ;
+
+  /* set aspect ratio */
+  if (pvr->aspect != -1)
+    codec.aspect = pvr->aspect;
+
+  /* if user value is given, we need to reset audio bitmask */
+  if ((pvr->samplerate != -1) || (pvr->layer != -1)
+      || (pvr->audio_rate != -1) || (pvr->audio_mode != -1))
+    codec.audio_bitmask = 0;
+  
+  /* set audio samplerate */
+  if (pvr->samplerate != -1)
+    codec.audio_bitmask |= pvr->samplerate;
+
+  /* set audio layer */
+  if (pvr->layer != -1)
+    codec.audio_bitmask |= pvr->layer;
+
+  /* set audio bitrate */
+  if (pvr->audio_rate != -1)
+    codec.audio_bitmask |= pvr->audio_rate;
+
+  /* set audio mode */
+  if (pvr->audio_mode != -1)
+    codec.audio_bitmask |= pvr->audio_mode;
+
+  /* set video bitrate */
+  if (pvr->bitrate != -1)
+    codec.bitrate = pvr->bitrate;
+
+  /* set video bitrate mode */
+  if (pvr->bitrate_mode != -1)
+    codec.bitrate_mode = pvr->bitrate_mode;
+
+  /* set video bitrate peak */
+  if (pvr->bitrate != -1)
+    codec.bitrate_peak = pvr->bitrate_peak;
+
+  /* set video stream type */
+  if (pvr->stream_type != -1)
+    codec.stream_type = pvr->stream_type;
+
+  /* set new encoding settings */
+  if (ioctl (pvr->dev_fd, IVTV_IOC_S_CODEC, &codec) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't set codec (%s).\n", LOG_LEVEL_IVTV, strerror (errno));
+    return -1;
+  }
+
+  return 0;
+}
+
+/* V4L2 layer */
+
+static void
+parse_v4l2_tv_options (struct pvr_t *pvr)
+{
+  if (!pvr)
+    return;
+  
+  if (tv_param_device)
+  {
+    if (pvr->video_dev)
+      free (pvr->video_dev);
+    pvr->video_dev = strdup (tv_param_device);
+  }
+  
+  if (tv_param_noaudio)
+    pvr->mute = tv_param_noaudio;
+
+  if (tv_param_input)
+    pvr->input = tv_param_input;
+  
+  if (tv_param_normid)
+    pvr->normid = tv_param_normid;
+  
+  if (tv_param_brightness)
+    pvr->brightness = tv_param_brightness;
+  
+  if (tv_param_contrast)
+    pvr->contrast = tv_param_contrast;
+  
+  if (tv_param_hue)
+    pvr->hue = tv_param_hue;
+  
+  if (tv_param_saturation)
+    pvr->saturation = tv_param_saturation;
+
+  if (tv_param_width)
+    pvr->width = tv_param_width;
+
+  if (tv_param_height)
+    pvr->height = tv_param_height;
+
+  if (tv_param_freq)
+    pvr->freq = strdup (tv_param_freq);
+}
+
+static int
+set_v4l2_settings (struct pvr_t *pvr)
+{
+  if (!pvr)
+    return -1;
+  
+  if (pvr->dev_fd < 0)
+    return -1;
+
+  /* -tv noaudio */
+  if (pvr->mute)
+  {
+    struct v4l2_control ctrl;
+    ctrl.id = V4L2_CID_AUDIO_MUTE;
+    ctrl.value = 1;
+    if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't mute (%s).\n", LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+  }
+
+  /* -tv input=x */
+  if (pvr->input != 0)
+  {
+    if (ioctl (pvr->dev_fd, VIDIOC_S_INPUT, &pvr->input) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set input (%s)\n", LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+  }
+  
+  /* -tv normid=x */
+  if (pvr->normid != -1)
+  {
+    struct v4l2_standard std;
+    std.index = pvr->normid;
+
+    if (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &std) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+
+    mp_msg (MSGT_OPEN, MSGL_V,
+            "%s set norm to %s\n", LOG_LEVEL_V4L2, std.name);
+
+    if (ioctl (pvr->dev_fd, VIDIOC_S_STD, &std.id) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+  }
+  
+  /* -tv brightness=x */
+  if (pvr->brightness != 0)
+  {
+    struct v4l2_control ctrl;
+    ctrl.id = V4L2_CID_BRIGHTNESS;
+    ctrl.value = pvr->brightness;
+
+    if (ctrl.value < 0)
+      ctrl.value = 0;
+    if (ctrl.value > 255)
+      ctrl.value = 255;
+    
+    if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set brightness to %d (%s).\n",
+              LOG_LEVEL_V4L2, ctrl.value, strerror (errno));
+      return -1;
+    }
+  }
+
+  /* -tv contrast=x */
+  if (pvr->contrast != 0)
+  {
+    struct v4l2_control ctrl;
+    ctrl.id = V4L2_CID_CONTRAST;
+    ctrl.value = pvr->contrast;
+
+    if (ctrl.value < 0)
+      ctrl.value = 0;
+    if (ctrl.value > 127)
+      ctrl.value = 127;
+    
+    if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set contrast to %d (%s).\n",
+              LOG_LEVEL_V4L2, ctrl.value, strerror (errno));
+      return -1;
+    }
+  }
+
+  /* -tv hue=x */
+  if (pvr->hue != 0)
+  {
+    struct v4l2_control ctrl;
+    ctrl.id = V4L2_CID_HUE;
+    ctrl.value = pvr->hue;
+
+    if (ctrl.value < -128)
+      ctrl.value = -128;
+    if (ctrl.value > 127)
+      ctrl.value = 127;
+    
+    if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set hue to %d (%s).\n",
+              LOG_LEVEL_V4L2, ctrl.value, strerror (errno));
+      return -1;
+    }
+  }
+  
+  /* -tv saturation=x */
+  if (pvr->saturation != 0)
+  {
+    struct v4l2_control ctrl;
+    ctrl.id = V4L2_CID_SATURATION;
+    ctrl.value = pvr->saturation;
+
+    if (ctrl.value < 0)
+      ctrl.value = 0;
+    if (ctrl.value > 127)
+      ctrl.value = 127;
+    
+    if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set saturation to %d (%s).\n",
+              LOG_LEVEL_V4L2, ctrl.value, strerror (errno));
+      return -1;
+    }
+  }
+  
+  /* -tv width=x:height=y */
+  if (pvr->width && pvr->height)
+  {
+    struct v4l2_format vfmt;
+    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    vfmt.fmt.pix.width = pvr->width;
+    vfmt.fmt.pix.height = pvr->height;
+
+    if (ioctl (pvr->dev_fd, VIDIOC_S_FMT, &vfmt) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't set resolution to %dx%d (%s).\n",
+              LOG_LEVEL_V4L2, pvr->width, pvr->height, strerror (errno));
+      return -1;
+    }
+  }
+
+  /* -tv freq=x */
+  if (pvr->freq)
+  {
+    struct v4l2_frequency vf;
+    vf.tuner = 0;
+    vf.type = 0;
+    vf.frequency = strtol (pvr->freq, 0L, 0);
+    mp_msg (MSGT_OPEN, MSGL_INFO,
+            "%s setting frequency to %d\n", LOG_LEVEL_V4L2, vf.frequency);
+    
+    if (ioctl (pvr->dev_fd, VIDIOC_S_FREQUENCY, &vf) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set frequency (%s).\n",
+              LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static int
+v4l2_list_capabilities (struct pvr_t *pvr)
+{
+  struct v4l2_audio vaudio;
+  struct v4l2_standard vs;
+  struct v4l2_input vin;
+  int err = 0;
+  
+  if (!pvr)
+    return -1;
+
+  if (pvr->dev_fd < 0)
+    return -1;
+  
+  /* list available video inputs */
+  vin.index = 0;
+  err = 1;
+  mp_msg (MSGT_OPEN, MSGL_INFO,
+          "%s Available video inputs: ", LOG_LEVEL_V4L2);
+  while (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) >= 0)
+  {
+    err = 0;
+    mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vin.index, vin.name);
+    vin.index++;
+  }
+  if (err)
+  {
+    mp_msg (MSGT_OPEN, MSGL_INFO, "none\n");
+    return -1;
+  }
+  else
+    mp_msg (MSGT_OPEN, MSGL_INFO, "\n");
+
+  /* list available audio inputs */
+  vaudio.index = 0;
+  err = 1;
+  mp_msg (MSGT_OPEN, MSGL_INFO,
+          "%s Available audio inputs: ", LOG_LEVEL_V4L2);
+  while (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) >= 0)
+  {
+    err = 0;
+    mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vaudio.index, vaudio.name);
+    vaudio.index++;
+  }
+  if (err)
+  {
+    mp_msg (MSGT_OPEN, MSGL_INFO, "none\n");
+    return -1;
+  }
+  else
+    mp_msg (MSGT_OPEN, MSGL_INFO, "\n");
+
+  /* list available norms */
+  vs.index = 0;
+  mp_msg (MSGT_OPEN, MSGL_INFO, "%s Available norms: ", LOG_LEVEL_V4L2);
+  while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0)
+  {
+    err = 0;
+    mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vs.index, vs.name);
+    vs.index++;
+  }
+  if (err)
+  {
+    mp_msg (MSGT_OPEN, MSGL_INFO, "none\n");
+    return -1;
+  }
+  else
+    mp_msg (MSGT_OPEN, MSGL_INFO, "\n");
+
+  return 0;
+}
+
+static int
+v4l2_display_settings (struct pvr_t *pvr)
+{
+  struct v4l2_audio vaudio;
+  struct v4l2_standard vs;
+  struct v4l2_input vin;
+  v4l2_std_id std;
+  int input;
+  
+  if (!pvr)
+    return -1;
+
+  if (pvr->dev_fd < 0)
+    return -1;
+
+  /* get current video input */
+  if (ioctl (pvr->dev_fd, VIDIOC_G_INPUT, &input) == 0)
+  {
+    vin.index = input;
+    if (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+    else
+      mp_msg (MSGT_OPEN, MSGL_INFO,
+              "%s Video input: %s\n", LOG_LEVEL_V4L2, vin.name);
+  }
+  else
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  /* get current audio input */
+  if (ioctl (pvr->dev_fd, VIDIOC_G_AUDIO, &vaudio) == 0)
+  {
+    vaudio.index = input;
+    if (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) < 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno));
+      return -1;
+    }
+    else
+      mp_msg (MSGT_OPEN, MSGL_INFO,
+              "%s Audio input: %s\n", LOG_LEVEL_V4L2, vaudio.name);
+  }
+  else
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  /* get current video format */
+  if (ioctl (pvr->dev_fd, VIDIOC_G_STD, &std) == 0)
+  {
+    vs.index = 0;
+
+    while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0)
+    {
+      if (vs.id == std)
+      {
+        mp_msg (MSGT_OPEN, MSGL_INFO,
+                "%s Norm: %s.\n", LOG_LEVEL_V4L2, vs.name);
+        break;
+      }
+      vs.index++;
+    }
+  }
+  else
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't get norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  return 0;
+}
+
+/* stream layer */
+
+static void
+pvr_stream_close (stream_t *stream)
+{
+  struct pvr_t *pvr;
+
+  if (!stream)
+    return;
+  
+  pvr = (struct pvr_t *) stream->priv;
+  pvr_uninit (pvr);
+}
+
+static int
+pvr_stream_read (stream_t *stream, char *buffer, int size)
+{
+  struct pollfd pfds[1];
+  struct pvr_t *pvr;
+  int rk, fd, pos;
+
+  if (!stream || !buffer)
+    return 0;
+  
+  pvr = (struct pvr_t *) stream->priv;
+  fd = pvr->dev_fd;
+  pos = 0;
+
+  if (fd < 0)
+    return 0;
+  
+  while (pos < size)
+  {
+    pfds[0].fd = fd;
+    pfds[0].events = POLLIN | POLLPRI;
+
+    rk = size - pos;
+
+    if (poll (pfds, 1, 500) <= 0)
+    {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s failed with errno %d when reading %d bytes\n",
+              LOG_LEVEL_PVR, errno, size-pos);
+      break;
+    }
+
+    rk = read (fd, &buffer[pos], rk);
+    if (rk > 0)
+    {
+      pos += rk;
+      mp_msg (MSGT_OPEN, MSGL_DBG3,
+              "%s read (%d) bytes\n", LOG_LEVEL_PVR, pos);
+    }
+  }
+		
+  if (!pos)
+    mp_msg (MSGT_OPEN, MSGL_ERR, "%s read %d bytes\n", LOG_LEVEL_PVR, pos);
+
+  return pos;
+}
+
+static int
+pvr_stream_open (stream_t *stream, int mode, void *opts, int *file_format)
+{
+  struct ivtv_ioctl_codec codec;
+  struct ivtv_driver_info info;
+  struct v4l2_capability vcap;
+  struct pvr_t *pvr = NULL;
+  
+  if (mode != STREAM_READ)
+    return STREAM_UNSUPORTED;
+  
+  pvr = pvr_init ();
+
+  parse_v4l2_tv_options (pvr);
+  parse_ivtv_options (pvr);
+  
+  /* open device */
+  pvr->dev_fd = open (pvr->video_dev, O_RDWR);
+  mp_msg (MSGT_OPEN, MSGL_INFO,
+          "%s Using device %s\n", LOG_LEVEL_PVR, pvr->video_dev);
+  if (pvr->dev_fd == -1)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s error opening device %s\n", LOG_LEVEL_PVR, pvr->video_dev);
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+  
+  /* query capabilities (i.e test V4L2 support) */
+  if (ioctl (pvr->dev_fd, VIDIOC_QUERYCAP, &vcap) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s device is not V4L2 compliant (%s).\n",
+            LOG_LEVEL_PVR, strerror (errno));
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+  else
+    mp_msg (MSGT_OPEN, MSGL_INFO,
+            "%s Detected %s\n", LOG_LEVEL_PVR, vcap.card);
+
+  /* get codec and initialize card (i.e test IVTV support) */
+  if (ioctl (pvr->dev_fd, IVTV_IOC_G_CODEC, &codec) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s device is not IVTV compliant (%s).\n",
+            LOG_LEVEL_PVR, strerror (errno));
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+  
+  /* get ivtv driver info */
+  if (ioctl (pvr->dev_fd, IVTV_IOC_G_DRIVER_INFO, &info) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s device is not IVTV compliant (%s).\n",
+            LOG_LEVEL_PVR, strerror (errno));
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+  else
+    mp_msg (MSGT_OPEN, MSGL_INFO,
+            "%s Detected ivtv driver: %s\n", LOG_LEVEL_PVR, info.comment);
+
+  /* list V4L2 capabilities */
+  if (v4l2_list_capabilities (pvr) == -1)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't get v4l2 capabilities\n", LOG_LEVEL_PVR);
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+  
+  /* apply V4L2 settings */
+  if (set_v4l2_settings (pvr) == -1)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't set v4l2 settings\n", LOG_LEVEL_PVR);
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+
+  /* apply IVTV settings */
+  if (set_ivtv_settings (pvr) == -1)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't set ivtv settings\n", LOG_LEVEL_PVR);
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+  
+  /* display current V4L2 settings */
+  if (v4l2_display_settings (pvr) == -1)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s can't get v4l2 settings\n", LOG_LEVEL_PVR);
+    pvr_uninit (pvr);
+    return STREAM_ERROR;
+  }
+
+  stream->priv = pvr;
+  stream->type = STREAMTYPE_PVR;
+  stream->fill_buffer = pvr_stream_read;
+  stream->close = pvr_stream_close;
+  
+  return STREAM_OK;
+}
+
+stream_info_t stream_info_pvr = {
+  "PVR (V4L2/IVTV) Input",
+  "pvr",
+  "Benjamin Zores",
+  "",
+  pvr_stream_open, 			
+  { "pvr", NULL },
+  NULL,
+  1
+};