/***************************************************************************** * v4l2.c : Video4Linux2 input module for vlc ***************************************************************************** * Copyright (C) 2002-2007 the VideoLAN team * $Id$ * * Author: Benjamin Pracht * Richard Hosking * * 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. *****************************************************************************/ /* * Sections based on the reference V4L2 capture example at * http://v4l2spec.bytesex.org/spec/capture-example.html */ /* * TODO: No mjpeg support yet. * TODO: Tuner partial implementation. * TODO: Alsa input support? */ /***************************************************************************** * Preamble *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include /***************************************************************************** * Module descriptior *****************************************************************************/ static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); #define DEV_TEXT N_("Device name") #define DEV_LONGTEXT N_( \ "Name of the device to use. " \ "If you don't specify anything, /dev/video0 will be used.") #define ADEV_TEXT N_("Audio device name") #define ADEV_LONGTEXT N_( \ "Name of the audio device to use. " \ "If you don't specify anything, no audio device will be used.") #define STANDARD_TEXT N_( "Standard" ) #define STANDARD_LONGTEXT N_( \ "Video standard (Default, SECAM, PAL, or NTSC)." ) #define CHROMA_TEXT N_("Video input chroma format") #define CHROMA_LONGTEXT N_( \ "Force the Video4Linux2 video device to use a specific chroma format " \ "(eg. I420, RV24, etc.)") #define INPUT_TEXT N_( "Input" ) #define INPUT_LONGTEXT N_( \ "Input of the card to use (Usually, 0 = tuner, " \ "1 = composite, 2 = svideo)." ) #define IOMETHOD_TEXT N_( "IO Method" ) #define IOMETHOD_LONGTEXT N_( \ "IO Method (READ, MMAP, USERPTR)." ) #define FPS_TEXT N_( "Framerate" ) #define FPS_LONGTEXT N_( "Framerate to capture, if applicable " \ "(-1 for autodetect)." ) #define STEREO_TEXT N_( "Stereo" ) #define STEREO_LONGTEXT N_( \ "Capture the audio stream in stereo." ) #define SAMPLERATE_TEXT N_( "Samplerate" ) #define SAMPLERATE_LONGTEXT N_( \ "Samplerate of the captured audio stream, in Hz (eg: 11025, 22050, 44100, 48000)" ) #define CACHING_TEXT N_("Caching value in ms") #define CACHING_LONGTEXT N_( \ "Caching value for V4L2 captures. This " \ "value should be set in milliseconds." ) typedef enum { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR, } io_method; static int i_standards_list[] = { V4L2_STD_UNKNOWN, V4L2_STD_SECAM, V4L2_STD_PAL, V4L2_STD_NTSC }; static const char *psz_standards_list_text[] = { N_("Default"), N_("SECAM"), N_("PAL"), N_("NTSC") }; static int i_iomethod_list[] = { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR }; static const char *psz_iomethod_list_text[] = { N_("READ"), N_("MMAP"), N_("USERPTR") }; vlc_module_begin(); set_shortname( _("Video4Linux2") ); set_description( _("Video4Linux2 input") ); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_ACCESS ); add_string( "v4l2-dev", "/dev/video0", 0, DEV_TEXT, DEV_LONGTEXT, VLC_FALSE ); add_string( "v4l2-adev", "/dev/dsp", 0, DEV_TEXT, DEV_LONGTEXT, VLC_FALSE ); add_integer( "v4l2-standard", 0, NULL, STANDARD_TEXT, STANDARD_LONGTEXT, VLC_FALSE ); change_integer_list( i_standards_list, psz_standards_list_text, 0 ); add_string( "v4l2-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, VLC_TRUE ); add_integer( "v4l2-input", 0, NULL, INPUT_TEXT, INPUT_LONGTEXT, VLC_TRUE ); add_integer( "v4l2-io", IO_METHOD_MMAP, NULL, IOMETHOD_TEXT, IOMETHOD_LONGTEXT, VLC_FALSE ); change_integer_list( i_iomethod_list, psz_iomethod_list_text, 0 ); add_float( "v4l2-fps", 0, NULL, FPS_TEXT, FPS_LONGTEXT, VLC_TRUE ); add_bool( "v4l2-stereo", VLC_TRUE, NULL, STEREO_TEXT, STEREO_LONGTEXT, VLC_TRUE ); add_integer( "v4l2-samplerate", 48000, NULL, SAMPLERATE_TEXT, SAMPLERATE_LONGTEXT, VLC_TRUE ); add_integer( "v4l2-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); add_shortcut( "v4l2" ); set_capability( "access_demux", 10 ); set_callbacks( Open, Close ); vlc_module_end(); /***************************************************************************** * Access: local prototypes *****************************************************************************/ static void ParseMRL( demux_t * ); static int Control( demux_t *, int, va_list ); static int Demux( demux_t * ); static block_t* GrabVideo( demux_t *p_demux ); static block_t* ProcessVideoFrame( demux_t *p_demux, uint8_t *p_frame ); static block_t* GrabAudio( demux_t *p_demux ); vlc_bool_t IsChromaSupported( demux_t *p_demux, unsigned int i_v4l2 ); unsigned int GetFourccFromString( char *psz_fourcc ); static int OpenVideoDev( demux_t *, char *psz_device ); static int OpenAudioDev( demux_t *, char *psz_device ); static vlc_bool_t ProbeVideoDev( demux_t *, char *psz_device ); static vlc_bool_t ProbeAudioDev( demux_t *, char *psz_device ); static struct { unsigned int i_v4l2; int i_fourcc; } v4l2chroma_to_fourcc[] = { { V4L2_PIX_FMT_GREY, VLC_FOURCC( 'G', 'R', 'E', 'Y' ) }, { V4L2_PIX_FMT_HI240, VLC_FOURCC( 'I', '2', '4', '0' ) }, { V4L2_PIX_FMT_RGB565, VLC_FOURCC( 'R', 'V', '1', '6' ) }, { V4L2_PIX_FMT_RGB555, VLC_FOURCC( 'R', 'V', '1', '5' ) }, { V4L2_PIX_FMT_BGR24, VLC_FOURCC( 'R', 'V', '2', '4' ) }, { V4L2_PIX_FMT_BGR32, VLC_FOURCC( 'R', 'V', '3', '2' ) }, { V4L2_PIX_FMT_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', '2' ) }, { V4L2_PIX_FMT_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', 'V' ) }, { V4L2_PIX_FMT_UYVY, VLC_FOURCC( 'U', 'Y', 'V', 'Y' ) }, { V4L2_PIX_FMT_Y41P, VLC_FOURCC( 'I', '4', '1', 'N' ) }, { V4L2_PIX_FMT_YUV422P, VLC_FOURCC( 'I', '4', '2', '2' ) }, { V4L2_PIX_FMT_YVU420, VLC_FOURCC( 'I', '4', '2', '0' ) }, { V4L2_PIX_FMT_YUV411P, VLC_FOURCC( 'I', '4', '1', '1' ) }, { V4L2_PIX_FMT_YUV410, VLC_FOURCC( 'I', '4', '1', '0' ) }, { 0, 0 } }; struct buffer_t { void * start; size_t length; void * orig_userp; }; struct demux_sys_t { char *psz_device; /* Main device from MRL, can be video or audio */ char *psz_vdev; int i_fd_video; char *psz_adev; int i_fd_audio; /* Video */ io_method io; int i_pts; struct v4l2_capability dev_cap; int i_input; struct v4l2_input *p_inputs; int i_selected_input; int i_standard; struct v4l2_standard *p_standards; v4l2_std_id i_selected_standard_id; int i_audio; /* V4L2 devices cannot have more than 32 audio inputs */ struct v4l2_audio p_audios[32]; int i_tuner; struct v4l2_tuner *p_tuners; int i_codec; struct v4l2_fmtdesc *p_codecs; struct buffer_t *p_buffers; unsigned int i_nbuffers; int i_width; int i_height; float f_fps; /* <= 0.0 mean to grab at full rate */ mtime_t i_video_pts; /* only used when f_fps > 0 */ int i_fourcc; picture_t pic; int i_video_frame_size; es_out_id_t *p_es_video; /* Audio */ int i_sample_rate; vlc_bool_t b_stereo; int i_audio_max_frame_size; block_t *p_block_audio; es_out_id_t *p_es_audio; }; /***************************************************************************** * Open: opens v4l2 device ***************************************************************************** * * url: