summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfigure38
-rw-r--r--etc/codecs.conf2
-rw-r--r--libao2/ao_v4l2.c159
-rw-r--r--libao2/audio_out.c6
-rw-r--r--libvo/video_out.c6
-rw-r--r--libvo/vo_v4l2.c262
6 files changed, 472 insertions, 1 deletions
diff --git a/configure b/configure
index 5c22f4a613..ffb52b070d 100755
--- a/configure
+++ b/configure
@@ -358,6 +358,7 @@ Video output:
--enable-dxr2 enable DXR2 video output [autodetect]
--enable-dxr3 enable DXR3/H+ video output [autodetect]
--enable-ivtv enable IVTV TV-Out video output [autodetect]
+ --enable-v4l2 enable V4L2 Decoder audio/video output [autodetect]
--enable-dvb enable DVB video output [autodetect]
--enable-dvbhead enable DVB video output (HEAD version) [autodetect]
--enable-mga enable mga_vid video output [disable]
@@ -539,6 +540,7 @@ _dvbhead=auto
_dxr2=auto
_dxr3=auto
_ivtv=auto
+_v4l2=auto
_iconv=auto
_langinfo=auto
_rtc=auto
@@ -846,6 +848,8 @@ for ac_option do
--disable-dxr3) _dxr3=no ;;
--enable-ivtv) _ivtv=yes ;;
--disable-ivtv) _ivtv=no ;;
+ --enable-v4l2) _v4l2=yes ;;
+ --disable-v4l2) _v4l2=no ;;
--enable-iconv) _iconv=yes ;;
--disable-iconv) _iconv=no ;;
--enable-langinfo) _langinfo=yes ;;
@@ -4823,6 +4827,39 @@ fi
echores "$_ivtv"
+echocheck "V4L2 MPEG Decoder"
+if test "$_v4l2" = auto ; then
+ cat > $TMPC << EOF
+#include <stdlib.h>
+#include <inttypes.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+int main(void) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ return 0;
+#else
+ return -1;
+#endif
+}
+EOF
+ _v4l2=no
+ cc_check && _v4l2=yes
+fi
+if test "$_v4l2" = yes ; then
+ _def_v4l2='#define HAVE_V4L2_DECODER 1'
+ _vosrc="$_vosrc vo_v4l2.c"
+ _vomodules="v4l2 $_vomodules"
+ _aosrc="$_aosrc ao_v4l2.c"
+ _aomodules="v4l2 $_aomodules"
+else
+ _def_v4l2='#undef HAVE_V4L2_DECODER'
+ _novomodules="v4l2 $_novomodules"
+ _noaomodules="v4l2 $_noaomodules"
+fi
+echores "$_v4l2"
+
+
#########
# AUDIO #
@@ -8241,6 +8278,7 @@ $_def_fbdev
$_def_dxr2
$_def_dxr3
$_def_ivtv
+$_def_v4l2
$_def_dvb
$_def_dvb_in
$_def_svga
diff --git a/etc/codecs.conf b/etc/codecs.conf
index b17446e6a0..c4f5d3fe96 100644
--- a/etc/codecs.conf
+++ b/etc/codecs.conf
@@ -35,7 +35,7 @@ videocodec zmbv
; Note: mpegpes is preferred for hw decoders:
videocodec mpegpes
- info "MPEG-PES output (.mpg or DXR3/IVTV/DVB card)"
+ info "MPEG-PES output (.mpg or DXR3/IVTV/DVB/V4L2 card)"
comment "for hardware decoding"
status working
format 0x10000001 ; mpeg 1
diff --git a/libao2/ao_v4l2.c b/libao2/ao_v4l2.c
new file mode 100644
index 0000000000..6dca333c1d
--- /dev/null
+++ b/libao2/ao_v4l2.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007 Benjamin Zores
+ * Audio output for V4L2 hardware MPEG decoders.
+ *
+ * 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
+ *
+ * WARNING: you need to force -ac hwmpa for audio output to work.
+ */
+
+#include <inttypes.h>
+
+#include "config.h"
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "audio_out.h"
+#include "audio_out_internal.h"
+#include "libaf/af_format.h"
+#include "libmpdemux/mpeg_packetizer.h"
+
+#define MPEG_AUDIO_ID 0x1C0
+
+static int freq = 0;
+
+static ao_info_t info =
+{
+ "V4L2 MPEG Audio Decoder output",
+ "v4l2",
+ "Benjamin Zores",
+ ""
+};
+
+LIBAO_EXTERN (v4l2)
+
+/* to set/get/query special features/parameters */
+static int
+control (int cmd,void *arg)
+{
+ return CONTROL_UNKNOWN;
+}
+
+/* open & setup audio device */
+static int
+init (int rate, int channels, int format, int flags)
+{
+ extern int v4l2_fd;
+
+ if (v4l2_fd < 0)
+ return 0;
+
+ if (format != AF_FORMAT_MPEG2)
+ {
+ mp_msg (MSGT_AO, MSGL_FATAL,
+ "AO: [v4l2] can only handle MPEG audio streams.\n");
+ return 0;
+ }
+
+ ao_data.outburst = 2048;
+ ao_data.samplerate = rate;
+ ao_data.channels = channels;
+ ao_data.format = AF_FORMAT_MPEG2;
+ ao_data.buffersize = 2048;
+ ao_data.bps = rate * 2 * 2;
+ ao_data.pts = 0;
+ freq = rate;
+
+ /* check for supported audio rate */
+ if (rate != 32000 || rate != 41000 || rate != 48000)
+ {
+ mp_msg (MSGT_AO, MSGL_ERR, MSGTR_AO_MPEGPES_UnsupSamplerate, rate);
+ rate = 48000;
+ }
+
+ return 1;
+}
+
+/* close audio device */
+static void
+uninit (int immed)
+{
+ /* nothing to do */
+}
+
+/* stop playing and empty buffers (for seeking/pause) */
+static void
+reset (void)
+{
+ /* nothing to do */
+}
+
+/* stop playing, keep buffers (for pause) */
+static void
+audio_pause (void)
+{
+ reset ();
+}
+
+/* resume playing, after audio_pause() */
+static void
+audio_resume (void)
+{
+ /* nothing to do */
+}
+
+/* how many bytes can be played without blocking */
+static int
+get_space (void)
+{
+ extern int vo_pts;
+ float x;
+ int y;
+
+ x = (float) (vo_pts - ao_data.pts) / 90000.0;
+ if (x <= 0)
+ return 0;
+
+ y = freq * 4 * x;
+ y /= ao_data.outburst;
+ y *= ao_data.outburst;
+
+ if (y > 32000)
+ y = 32000;
+
+ return y;
+}
+
+/* number of bytes played */
+static int
+play (void *data, int len, int flags)
+{
+ extern int v4l2_write (unsigned char *data, int len);
+
+ if (ao_data.format != AF_FORMAT_MPEG2)
+ return 0;
+
+ send_mpeg_pes_packet (data, len, MPEG_AUDIO_ID, ao_data.pts, 2, v4l2_write);
+
+ return len;
+}
+
+/* delay in seconds between first and last sample in buffer */
+static float
+get_delay (void)
+{
+ return 0.0;
+}
diff --git a/libao2/audio_out.c b/libao2/audio_out.c
index 7546f43095..4cf00726ec 100644
--- a/libao2/audio_out.c
+++ b/libao2/audio_out.c
@@ -68,6 +68,9 @@ extern ao_functions_t audio_out_dxr2;
#ifdef HAVE_IVTV
extern ao_functions_t audio_out_ivtv;
#endif
+#ifdef HAVE_V4L2_DECODER
+extern ao_functions_t audio_out_v4l2;
+#endif
extern ao_functions_t audio_out_mpegpes;
extern ao_functions_t audio_out_pcm;
extern ao_functions_t audio_out_pss;
@@ -131,6 +134,9 @@ ao_functions_t* audio_out_drivers[] =
#ifdef HAVE_IVTV
&audio_out_ivtv,
#endif
+#ifdef HAVE_V4L2_DECODER
+ &audio_out_v4l2,
+#endif
&audio_out_null,
// should not be auto-selected:
&audio_out_pcm,
diff --git a/libvo/video_out.c b/libvo/video_out.c
index 4b85b99a46..14899b82a5 100644
--- a/libvo/video_out.c
+++ b/libvo/video_out.c
@@ -103,6 +103,9 @@ extern vo_functions_t video_out_dxr3;
#ifdef HAVE_IVTV
extern vo_functions_t video_out_ivtv;
#endif
+#ifdef HAVE_V4L2_DECODER
+extern vo_functions_t video_out_v4l2;
+#endif
#ifdef HAVE_JPEG
extern vo_functions_t video_out_jpeg;
#endif
@@ -214,6 +217,9 @@ vo_functions_t* video_out_drivers[] =
#ifdef HAVE_IVTV
&video_out_ivtv,
#endif
+#ifdef HAVE_V4L2_DECODER
+ &video_out_v4l2,
+#endif
#ifdef HAVE_ZR
&video_out_zr,
&video_out_zr2,
diff --git a/libvo/vo_v4l2.c b/libvo/vo_v4l2.c
new file mode 100644
index 0000000000..65dd22ac35
--- /dev/null
+++ b/libvo/vo_v4l2.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2007 Benjamin Zores
+ * Video output for V4L2 hardware MPEG decoders.
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+
+#include "mp_msg.h"
+#include "subopt-helper.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "libmpdemux/mpeg_packetizer.h"
+
+#define DEFAULT_MPEG_DECODER "/dev/video16"
+#define V4L2_VO_HDR "VO: [v4l2]"
+
+int v4l2_fd = -1;
+static vo_mpegpes_t *pes;
+
+/* suboptions */
+static int output = -1;
+static char *device = NULL;
+
+static opt_t subopts[] = {
+ {"output", OPT_ARG_INT, &output, (opt_test_f)int_non_neg},
+ {"device", OPT_ARG_MSTRZ, &device, NULL},
+ {NULL}
+};
+
+static vo_info_t info =
+{
+ "V4L2 MPEG Video Decoder Output",
+ "v4l2",
+ "Benjamin Zores",
+ ""
+};
+LIBVO_EXTERN (v4l2)
+
+int
+v4l2_write (unsigned char *data, int len)
+{
+ if (v4l2_fd < 0)
+ return 0;
+
+ return write (v4l2_fd, data, len);
+}
+
+/* video out functions */
+
+static int
+config (uint32_t width, uint32_t height,
+ uint32_t d_width, uint32_t d_height,
+ uint32_t fullscreen, char *title, uint32_t format)
+{
+ return 0;
+}
+
+static int
+preinit (const char *arg)
+{
+ struct v4l2_output vout;
+ struct v4l2_ext_controls ctrls;
+ int err;
+
+ if (subopt_parse (arg, subopts) != 0)
+ {
+ mp_msg (MSGT_VO, MSGL_FATAL,
+ "\n-vo v4l2 command line help:\n"
+ "Example: mplayer -vo v4l2:device=/dev/video16:output=2\n"
+ "\nOptions:\n"
+ " device=/dev/videoX\n"
+ " Name of the MPEG decoder device file.\n"
+ " output=<0-...>\n"
+ " V4L2 id of the TV output.\n"
+ "\n" );
+ return -1;
+ }
+
+ if (!device)
+ device = strdup (DEFAULT_MPEG_DECODER);
+
+ v4l2_fd = open (device, O_RDWR);
+ if (v4l2_fd < 0)
+ {
+ free (device);
+ mp_msg (MSGT_VO, MSGL_FATAL, "%s %s\n", V4L2_VO_HDR, strerror (errno));
+ return -1;
+ }
+
+ /* check for device hardware MPEG decoding capability */
+ ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
+ ctrls.count = 0;
+ ctrls.controls = NULL;
+
+ if (ioctl (v4l2_fd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
+ {
+ free (device);
+ mp_msg (MSGT_OPEN, MSGL_FATAL, "%s %s\n", V4L2_VO_HDR, strerror (errno));
+ return -1;
+ }
+
+ /* list available outputs */
+ vout.index = 0;
+ err = 1;
+ mp_msg (MSGT_VO, MSGL_INFO, "%s Available video outputs: ", V4L2_VO_HDR);
+ while (ioctl (v4l2_fd, VIDIOC_ENUMOUTPUT, &vout) >= 0)
+ {
+ err = 0;
+ mp_msg (MSGT_VO, MSGL_INFO, "'#%d, %s' ", vout.index, vout.name);
+ vout.index++;
+ }
+ if (err)
+ {
+ mp_msg (MSGT_VO, MSGL_INFO, "none\n");
+ free (device);
+ return -1;
+ }
+ else
+ mp_msg (MSGT_VO, MSGL_INFO, "\n");
+
+ /* set user specified output */
+ if (output != -1)
+ {
+ if (ioctl (v4l2_fd, VIDIOC_S_OUTPUT, &output) < 0)
+ {
+ mp_msg (MSGT_VO, MSGL_ERR,
+ "%s can't set output (%s)\n", V4L2_VO_HDR, strerror (errno));
+ free (device);
+ return -1;
+ }
+ }
+
+ /* display device name */
+ mp_msg (MSGT_VO, MSGL_INFO, "%s using %s\n", V4L2_VO_HDR, device);
+ free (device);
+
+ /* display current video output */
+ if (ioctl (v4l2_fd, VIDIOC_G_OUTPUT, &output) == 0)
+ {
+ vout.index = output;
+ if (ioctl (v4l2_fd, VIDIOC_ENUMOUTPUT, &vout) < 0)
+ {
+ mp_msg (MSGT_VO, MSGL_ERR,
+ "%s can't get output (%s).\n", V4L2_VO_HDR, strerror (errno));
+ return -1;
+ }
+ else
+ mp_msg (MSGT_VO, MSGL_INFO,
+ "%s video output: %s\n", V4L2_VO_HDR, vout.name);
+ }
+ else
+ {
+ mp_msg (MSGT_VO, MSGL_ERR,
+ "%s can't get output (%s).\n", V4L2_VO_HDR, strerror (errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+draw_osd (void)
+{
+ /* do nothing */
+}
+
+static int
+draw_frame (uint8_t * src[])
+{
+ pes = (vo_mpegpes_t *) src[0];
+ return 0;
+}
+
+static void
+flip_page (void)
+{
+ if (v4l2_fd < 0)
+ return;
+
+ if (!pes)
+ return;
+
+ send_mpeg_pes_packet (pes->data, pes->size, pes->id,
+ pes->timestamp ? pes->timestamp : vo_pts, 2,
+ v4l2_write);
+
+ /* ensure flip_page() won't be called twice */
+ pes = NULL;
+}
+
+static int
+draw_slice (uint8_t *image[], int stride[], int w, int h, int x, int y)
+{
+ return 0;
+}
+
+static void
+uninit (void)
+{
+ if (v4l2_fd < 0)
+ return;
+
+ /* close device */
+ close (v4l2_fd);
+ v4l2_fd = -1;
+}
+
+static void
+check_events (void)
+{
+ /* do nothing */
+}
+
+static int
+query_format (uint32_t format)
+{
+ if (format != IMGFMT_MPEGPES)
+ return 0;
+
+ return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_TIMER;
+}
+
+static int
+control (uint32_t request, void *data, ...)
+{
+ switch (request)
+ {
+ case VOCTRL_QUERY_FORMAT:
+ return query_format (*((uint32_t*) data));
+ }
+
+ return VO_NOTIMPL;
+}