summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cfg-common.h30
-rwxr-xr-xconfigure33
-rw-r--r--libmpdemux/Makefile3
-rw-r--r--libmpdemux/stream.c6
-rw-r--r--libmpdemux/stream.h1
-rw-r--r--libmpdemux/stream_pvr.c1026
6 files changed, 1099 insertions, 0 deletions
diff --git a/cfg-common.h b/cfg-common.h
index fb7415cc0f..1c7008b5bc 100644
--- a/cfg-common.h
+++ b/cfg-common.h
@@ -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 @@ m_option_t tvopts_conf[]={
};
#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[];
diff --git a/configure b/configure
index f0336429dc..abcdb589db 100755
--- a/configure
+++ b/configure
@@ -221,6 +221,7 @@ Optional features:
--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=yes
_tv_v4l=auto
_tv_v4l2=auto
_tv_bsdbt848=auto
+_pvr=auto
_network=yes
_winsock2=auto
_smbsupport=auto
@@ -1877,6 +1879,8 @@ for ac_option do
--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 @@ fi
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 = $_tv
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 @@ $_def_tv_v4l2
/* 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
diff --git a/libmpdemux/Makefile b/libmpdemux/Makefile
index 02b2203b7a..b229f4aba7 100644
--- a/libmpdemux/Makefile
+++ b/libmpdemux/Makefile
@@ -74,6 +74,9 @@ SRCS += tv.c frequencies.c tvi_dummy.c
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
diff --git a/libmpdemux/stream.c b/libmpdemux/stream.c
index a31c6a5136..f1b12ae827 100644
--- a/libmpdemux/stream.c
+++ b/libmpdemux/stream.c
@@ -54,6 +54,9 @@ extern stream_info_t stream_info_http2;
#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 @@ stream_info_t* auto_open_streams[] = {
#ifdef HAS_DVBIN_SUPPORT
&stream_info_dvb,
#endif
+#ifdef HAVE_PVR
+ &stream_info_pvr,
+#endif
#ifdef HAVE_FTP
&stream_info_ftp,
#endif
diff --git a/libmpdemux/stream.h b/libmpdemux/stream.h
index 79ef2b3a00..acbdc8f5a3 100644
--- a/libmpdemux/stream.h
+++ b/libmpdemux/stream.h
@@ -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
diff --git a/libmpdemux/stream_pvr.c b/libmpdemux/stream_pvr.c
new file mode 100644
index 0000000000..f060b94796
--- /dev/null
+++ b/libmpdemux/stream_pvr.c
@@ -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);