From: Darren S. <li...@yo...> - 2010-01-26 02:25:38
|
# HG changeset patch # User Darren Salt <li...@yo...> # Date 1264469672 0 # Node ID 5114af3add0b613deed376c0046ff20c94bb9734 # Parent 67d0f635f7fc727c226eb0f393fb9c804eed6b93 # Parent aa5435b07c86d23cc300182ee781b15f506fa0dc Merge v4l2 support. diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -676,10 +676,10 @@ dnl Check for usable video-for-linux (v4l) support dnl ---------------------------------------------- AC_ARG_ENABLE([v4l], - AS_HELP_STRING([--disable-v4l], [do not build Video4Linux input plugin])) + AS_HELP_STRING([--disable-v4l], [do not build Video4Linux input plugins])) if test "x$enable_v4l" != "xno"; then - AC_CHECK_HEADERS([linux/videodev.h], [have_v4l=yes], [have_v4l=no]) + AC_CHECK_HEADERS([linux/videodev.h linux/videodev2.h], [have_v4l=yes], [have_v4l=no]) AC_CHECK_HEADERS([asm/types.h]) if test "x$enable_v4l" = "xyes" && test "x$have_v4l" = "xno"; then AC_MSG_ERROR([Video4Linux support requested, but prerequisite headers not found.]) @@ -687,6 +687,20 @@ fi AM_CONDITIONAL(HAVE_V4L, [test "x$have_v4l" = "xyes"]) + +dnl ---------------------------------------------- +dnl Check for libv4l support +dnl ---------------------------------------------- +AC_ARG_ENABLE([libv4l], + AS_HELP_STRING([--disable-libv4l], [do not build with libv4l support])) + +if test "x$enable_libv4l" != "xno"; then + AC_CHECK_HEADERS([libv4l2.h], [have_libv4l=yes], [have_libv4l=no]) + if test "x$enable_libv4l" = "xyes" && test "x$have_libv4l" = "xno"; then + AC_MSG_ERROR([libv4l requested but not found.]) + fi +fi + dnl ---------------------------------------------- dnl Check for Xv and XvMC support diff --git a/doc/man/en/xine.5 b/doc/man/en/xine.5 --- a/doc/man/en/xine.5 +++ b/doc/man/en/xine.5 @@ -50,6 +50,8 @@ \(bu Video devices: .br .BI v4l://[ tuner_device / frequency ] +.br +.BI v4l2:// tuner_device .br .BI dvb:// channel_number .br diff --git a/src/input/Makefile.am b/src/input/Makefile.am --- a/src/input/Makefile.am +++ b/src/input/Makefile.am @@ -21,6 +21,7 @@ if HAVE_V4L in_v4l = xineplug_inp_v4l.la +in_v4l2 = xineplug_inp_v4l2.la in_pvr = xineplug_inp_pvr.la endif @@ -60,6 +61,7 @@ $(in_dvd) \ $(in_vcd) \ $(in_v4l) \ + $(in_v4l2) \ $(in_gnome_vfs) \ $(in_smb) \ xineplug_inp_mms.la \ @@ -138,6 +140,11 @@ xineplug_inp_v4l_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) xineplug_inp_v4l_la_LDFLAGS = -avoid-version -module +xineplug_inp_v4l2_la_SOURCES = input_v4l2.c +xineplug_inp_v4l2_la_LIBADD = $(XINE_LIB) $(ALSA_LIBS) +xineplug_inp_v4l2_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) +xineplug_inp_v4l2_la_LDFLAGS = -avoid-version -module + xineplug_inp_gnome_vfs_la_SOURCES = input_gnome_vfs.c net_buf_ctrl.c xineplug_inp_gnome_vfs_la_LIBADD = $(XINE_LIB) $(GNOME_VFS_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL) xineplug_inp_gnome_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) diff --git a/src/input/input_v4l2.c b/src/input/input_v4l2.c new file mode 100644 --- /dev/null +++ b/src/input/input_v4l2.c @@ -0,0 +1,438 @@ +/* +* Copyright (C) 2010 the xine project +* Copyright (C) 2010 Trever Fischer <tdf...@fe...> +* +* This file is part of xine, a free video player. +* +* xine 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. +* +* xine 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, USA +* +* v4l2 input plugin +*/ + +#define LOG_MODULE "v4l2" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define LOG + +#include "input_plugin.h" +#include "xine_plugin.h" +#include "xine_internal.h" + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <linux/videodev2.h> +#include <sys/mman.h> +#include <stdio.h> +#include <errno.h> + +#ifdef HAVE_LIBV4L2_H +# include <libv4l2.h> +#else +# include <unistd.h> +# include <sys/ioctl.h> +# define v4l2_open(f,d) open(f,d) +# define v4l2_ioctl(f,c,a) ioctl(f,c,a) +# define v4l2_mmap(p,l,d,m,f,o) mmap(p,l,d,m,f,o) +# define v4l2_munmap(s,l) munmap(s,l) +# define v4l2_close(f) close(f) +#endif + +typedef struct { + void *start; + size_t length; +} buffer_data; + +typedef struct { + int width; + int height; +} resolution_t; + +typedef struct { + buffer_data *buffers; + int bufcount; + resolution_t resolution; + struct v4l2_buffer inbuf; + off_t index; + int headerSent; +} v4l2_video_t; + +typedef struct { + buffer_data *buffers; + int bufcount; +} v4l2_radio_t; + +typedef struct { + input_plugin_t input_plugin; + + int fd; + char* mrl; + struct v4l2_capability cap; + xine_stream_t *stream; + + xine_event_queue_t *events; + v4l2_video_t* video; + v4l2_radio_t* radio; +} v4l2_input_plugin_t; + +static void v4l2_input_enqueue_video_buffer(v4l2_input_plugin_t *this, int idx); +static int v4l2_input_dequeue_video_buffer(v4l2_input_plugin_t *this, buf_element_t *input); +static int v4l2_input_setup_video_streaming(v4l2_input_plugin_t *this); + + +static int v4l2_input_open(input_plugin_t *this_gen) { + v4l2_input_plugin_t *this = (v4l2_input_plugin_t*) this_gen; + lprintf("Opening %s\n", this->mrl); + this->fd = v4l2_open(this->mrl, O_RDWR); + if (this->fd) { + /* TODO: Clean up this mess */ + this->events = xine_event_new_queue(this->stream); + v4l2_ioctl(this->fd, VIDIOC_QUERYCAP, &(this->cap)); + if (this->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + this->video = malloc(sizeof(v4l2_video_t)); + this->video->headerSent = 0; + this->video->bufcount = 0; + } + if (this->cap.capabilities & V4L2_CAP_STREAMING) { + lprintf("Supports streaming. Allocating buffers...\n"); + if (this->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + if (v4l2_input_setup_video_streaming(this)) { + lprintf("Video streaming ready.\n"); + return 1; + } else { + /* TODO: Fallbacks */ + lprintf("Video streaming setup failed.\n"); + return 0; + } + } else { [... 187 lines omitted ...] + } + v4l2_close(this->fd); + free(this->mrl); + free(this); +} + +static off_t v4l2_input_read(input_plugin_t *this_gen, char *buf, off_t nlen) { + /* Only block reads are supported. */ + return 0; +} + +static uint32_t v4l2_input_get_capabilities(input_plugin_t* this_gen) { + return INPUT_CAP_BLOCK; +} + +static const char* v4l2_input_get_mrl(input_plugin_t* this_gen) { + v4l2_input_plugin_t* this = (v4l2_input_plugin_t*)this_gen; + /* HACK HACK HACK HACK */ + /* So far, the only way to get the yuv_frames demuxer to work with this */ + return "v4l:/"; + //return this->mrl; +} + +static int v4l2_input_get_optional_data(input_plugin_t *this_gen, void *data, int data_type) { + return INPUT_OPTIONAL_UNSUPPORTED; +} + +/* Seeking not supported. */ +static off_t v4l2_input_seek(input_plugin_t *this_gen, off_t offset, int origin) { + return -1; +} + +static off_t v4l2_input_seek_time(input_plugin_t *this_gen, int time_offset, int origin) { + return -1; +} + +static off_t v4l2_input_pos(input_plugin_t *this_gen) { + /* TODO */ + return 0; +} + +static int v4l2_input_time(input_plugin_t *this_gen) { + /* TODO */ + return 0; +} + +static off_t v4l2_input_length(input_plugin_t *this_gen) { + return -1; +} + +typedef struct { + input_class_t input_class; +} v4l2_input_class_t; + +static input_plugin_t *v4l2_class_get_instance(input_class_t *gen_cls, xine_stream_t *stream, const char *mrl) { + v4l2_input_plugin_t *this; + if (strncasecmp (mrl, "v4l2:/", 6)) + return NULL; + mrl += 5; + while (*++mrl == '/') /**/; + --mrl; /* point at the last slash */ + /* TODO: Radio devices */ + /* FIXME: Don't require devices to be of /dev/videoXXX */ + if (strncmp(mrl, "/dev/video", 10) != 0) + return NULL; + lprintf("We can handle %s!\n", mrl); + + this = calloc(1, sizeof(v4l2_input_plugin_t)); + _x_assert(this); + this->mrl = strdup(mrl); + this->input_plugin.open = v4l2_input_open; + this->input_plugin.get_capabilities = v4l2_input_get_capabilities; + this->input_plugin.get_blocksize = v4l2_input_blocksize; + this->input_plugin.get_mrl = v4l2_input_get_mrl; + this->input_plugin.dispose = v4l2_input_dispose; + this->input_plugin.read = v4l2_input_read; + this->input_plugin.read_block = v4l2_input_read_block; + this->input_plugin.seek = v4l2_input_seek; + this->input_plugin.seek_time = v4l2_input_seek_time; + this->input_plugin.get_current_pos = v4l2_input_pos; + this->input_plugin.get_current_time = v4l2_input_time; + this->input_plugin.get_length = v4l2_input_length; + this->input_plugin.get_optional_data = v4l2_input_get_optional_data; + this->input_plugin.input_class = gen_cls; + this->stream = stream; + + this->video = NULL; + this->radio = NULL; + lprintf("Ready to read!\n"); + + return &this->input_plugin; +} + +static const char *v4l2_class_get_description(input_class_t *this_gen) { + /* TODO: Translatable with _() */ + return "v4l2 input plugin"; +} + +static const char *v4l2_class_get_identifier(input_class_t *this_gen) { + return "v4l2"; +} + +static void v4l2_class_dispose(input_class_t *this_gen) { + free(this_gen); +} + +static void *v4l2_init_class(xine_t *xine, void *data) { + v4l2_input_class_t *this; + this = malloc(sizeof(v4l2_input_class_t)); + this->input_class.get_instance = v4l2_class_get_instance; + this->input_class.get_description = v4l2_class_get_description; + this->input_class.get_identifier = v4l2_class_get_identifier; + this->input_class.get_dir = NULL; + this->input_class.get_autoplay_list = NULL; + this->input_class.dispose = v4l2_class_dispose; + this->input_class.eject_media = NULL; + return &this->input_class; +} + +const input_info_t input_info_v4l2 = { + 4000 +}; + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_INPUT, 17, "v4l2", XINE_VERSION_CODE, &input_info_v4l2, v4l2_init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; |