📄 v4l.c
字号:
/***************************************************************************** * v4l.c : Video4Linux input module for vlc ***************************************************************************** * Copyright (C) 2002-2004 VideoLAN * $Id: v4l.c,v 1.41 2004/02/12 17:52:48 fenrir Exp $ * * Author: Laurent Aimar <fenrir@via.ecp.fr> * Paul Forgey <paulf at aphrodite dot com> * Gildas Bazin <gbazin@netcourrier.com> * * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc/vout.h>#include <codecs.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <unistd.h>#include <sys/mman.h>#include <errno.h>#include <fcntl.h>/* From GStreamer's v4l plugin: * Because of some really cool feature in video4linux1, also known as * 'not including sys/types.h and sys/time.h', we had to include it * ourselves. In all their intelligence, these people decided to fix * this in the next version (video4linux2) in such a cool way that it * breaks all compilations of old stuff... * The real problem is actually that linux/time.h doesn't use proper * macro checks before defining types like struct timeval. The proper * fix here is to either fuck the kernel header (which is what we do * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it * upstream, which I'll consider doing later on. If you get compiler * errors here, check your linux/time.h && sys/time.h header setup.*/#define _LINUX_TIME_H#include <linux/videodev.h>#include "videodev_mjpeg.h"#include <sys/soundcard.h>/***************************************************************************** * Module descriptior *****************************************************************************/static int AccessOpen ( vlc_object_t * );static void AccessClose( vlc_object_t * );static int DemuxOpen ( vlc_object_t * );static void DemuxClose ( vlc_object_t * );#define CACHING_TEXT N_("Caching value in ms")#define CACHING_LONGTEXT N_( \ "Allows you to modify the default caching value for v4l streams. This " \ "value should be set in millisecond units." )#define VDEV_TEXT N_("Video device name")#define VDEV_LONGTEXT N_( \ "Specify the name of the video device that will be used. " \ "If you don't specify anything, no video device will be used.")#define ADEV_TEXT N_("Audio device name")#define ADEV_LONGTEXT N_( \ "Specify the name of the audio device that will be used. " \ "If you don't specify anything, no audio device will be used.")#define CHROMA_TEXT N_("Video input chroma format")#define CHROMA_LONGTEXT N_( \ "Force the Video4Linux video device to use a specific chroma format " \ "(eg. I420 (default), RV24, etc.)")vlc_module_begin(); set_description( _("Video4Linux input") ); add_integer( "v4l-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); add_string( "v4l-vdev", "/dev/video", 0, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE ); add_string( "v4l-adev", "/dev/dsp", 0, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE ); add_string( "v4l-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, VLC_TRUE ); add_shortcut( "v4l" ); set_capability( "access", 10 ); set_callbacks( AccessOpen, AccessClose ); add_submodule(); set_description( _("Video4Linux demuxer") ); add_shortcut( "v4l" ); set_capability( "demux", 200 ); set_callbacks( DemuxOpen, DemuxClose );vlc_module_end();/***************************************************************************** * Access: local prototypes *****************************************************************************/static int Read ( input_thread_t *, byte_t *, size_t );static void ParseMRL ( input_thread_t * );static int OpenVideoDev( input_thread_t *, char * );static int OpenAudioDev( input_thread_t *, char * );#define MJPEG_BUFFER_SIZE (256*1024)struct quicktime_mjpeg_app1{ uint32_t i_reserved; /* set to 0 */ uint32_t i_tag; /* 'mjpg' */ uint32_t i_field_size; /* offset following EOI */ uint32_t i_padded_field_size; /* offset following EOI+pad */ uint32_t i_next_field; /* offset to next field */ uint32_t i_DQT_offset; uint32_t i_DHT_offset; uint32_t i_SOF_offset; uint32_t i_SOS_offset; uint32_t i_data_offset; /* following SOS marker data */};static struct{ int i_v4l; int i_fourcc;} v4lchroma_to_fourcc[] ={ { VIDEO_PALETTE_GREY, VLC_FOURCC( 'G', 'R', 'E', 'Y' ) }, { VIDEO_PALETTE_HI240, VLC_FOURCC( 'I', '2', '4', '0' ) }, { VIDEO_PALETTE_RGB565, VLC_FOURCC( 'R', 'V', '1', '6' ) }, { VIDEO_PALETTE_RGB555, VLC_FOURCC( 'R', 'V', '1', '5' ) }, { VIDEO_PALETTE_RGB24, VLC_FOURCC( 'R', 'V', '2', '4' ) }, { VIDEO_PALETTE_RGB32, VLC_FOURCC( 'R', 'V', '3', '2' ) }, { VIDEO_PALETTE_YUV422, VLC_FOURCC( 'I', '4', '2', '2' ) }, { VIDEO_PALETTE_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', 'V' ) }, { VIDEO_PALETTE_UYVY, VLC_FOURCC( 'U', 'Y', 'V', 'Y' ) }, { VIDEO_PALETTE_YUV420, VLC_FOURCC( 'I', '4', '2', 'N' ) }, { VIDEO_PALETTE_YUV411, VLC_FOURCC( 'I', '4', '1', 'N' ) }, { VIDEO_PALETTE_RAW, VLC_FOURCC( 'G', 'R', 'A', 'W' ) }, { VIDEO_PALETTE_YUV422P, VLC_FOURCC( 'I', '4', '2', '2' ) }, { VIDEO_PALETTE_YUV420P, VLC_FOURCC( 'I', '4', '2', '0' ) }, { VIDEO_PALETTE_YUV411P, VLC_FOURCC( 'I', '4', '1', '1' ) }, { 0, 0 }};struct access_sys_t{ /* Devices */ char *psz_device; /* Main device from MRL, can be video or audio */ char *psz_vdev; int fd_video; char *psz_adev; int fd_audio; /* Video properties */ picture_t pic; int i_fourcc; int i_channel; int i_audio; int i_norm; int i_tuner; int i_frequency; int i_width; int i_height; int i_brightness; int i_hue; int i_colour; int i_contrast; float f_fps; /* <= 0.0 mean to grab at full rate */ mtime_t i_video_pts; /* only used when f_fps > 0 */ vlc_bool_t b_mjpeg; int i_decimation; int i_quality; struct video_capability vid_cap; struct video_mbuf vid_mbuf; struct mjpeg_requestbuffers mjpeg_buffers; uint8_t *p_video_mmap; int i_frame_pos; struct video_mmap vid_mmap; struct video_picture vid_picture; uint8_t *p_video_frame; int i_video_frame_size; int i_video_frame_size_allocated; /* Audio properties */ vlc_fourcc_t i_acodec_raw; int i_sample_rate; vlc_bool_t b_stereo; uint8_t *p_audio_frame; int i_audio_frame_size; int i_audio_frame_size_allocated; /* header */ int i_streams; int i_header_size; int i_header_pos; uint8_t *p_header; // at lest 8 bytes allocated /* data */ int i_data_size; int i_data_pos; uint8_t *p_data; // never allocated};/* * header: * fcc ".v4l" * u32 stream count * fcc "auds"|"vids" 0 * fcc codec 4 * if vids * u32 width 8 * u32 height 12 * u32 padding 16 * if auds * u32 channels 12 * u32 samplerate 8 * u32 samplesize 16 * * data: * u32 stream number * u32 data size * u8 data */static void SetDWBE( uint8_t *p, uint32_t dw ){ p[0] = (dw >> 24)&0xff; p[1] = (dw >> 16)&0xff; p[2] = (dw >> 8)&0xff; p[3] = (dw )&0xff;}static void SetQWBE( uint8_t *p, uint64_t qw ){ SetDWBE( p, (qw >> 32)&0xffffffff ); SetDWBE( &p[4], qw&0xffffffff);}/***************************************************************************** * AccessOpen: opens v4l device ***************************************************************************** * * url: <video device>:::: * *****************************************************************************/static int AccessOpen( vlc_object_t *p_this ){ input_thread_t *p_input = (input_thread_t *)p_this; access_sys_t *p_sys; vlc_value_t val; /* create access private data */ p_input->p_access_data = p_sys = malloc( sizeof( access_sys_t ) ); memset( p_sys, 0, sizeof( access_sys_t ) ); p_sys->i_audio = -1; p_sys->i_norm = VIDEO_MODE_AUTO; // auto p_sys->i_tuner = -1; p_sys->i_frequency = -1; p_sys->f_fps = -1.0; p_sys->i_video_pts = -1; p_sys->i_brightness = -1; p_sys->i_hue = -1; p_sys->i_colour = -1; p_sys->i_contrast = -1; p_sys->b_mjpeg = VLC_FALSE; p_sys->i_decimation = 1; p_sys->i_quality = 100; p_sys->i_video_frame_size_allocated = 0; p_sys->i_frame_pos = 0; p_sys->p_audio_frame = 0; p_sys->i_sample_rate = 44100; p_sys->b_stereo = VLC_TRUE; p_sys->p_header = NULL; p_sys->i_data_size = 0; p_sys->i_data_pos = 0; p_sys->p_data = NULL; p_sys->psz_device = p_sys->psz_vdev = p_sys->psz_adev = NULL; p_sys->fd_video = -1; p_sys->fd_audio = -1; ParseMRL( p_input ); /* Find main device (video or audio) */ if( p_sys->psz_device && *p_sys->psz_device ) { msg_Dbg( p_input, "main device=`%s'", p_sys->psz_device ); /* Try to open as video device */ p_sys->fd_video = OpenVideoDev( p_input, p_sys->psz_device ); if( p_sys->fd_video < 0 ) { /* Try to open as audio device */ p_sys->fd_audio = OpenAudioDev( p_input, p_sys->psz_device ); if( p_sys->fd_audio >= 0 ) { if( p_sys->psz_adev ) free( p_sys->psz_adev ); p_sys->psz_adev = p_sys->psz_device; p_sys->psz_device = NULL; } } else { if( p_sys->psz_vdev ) free( p_sys->psz_vdev ); p_sys->psz_vdev = p_sys->psz_device; p_sys->psz_device = NULL; } } /* If no device opened, only continue if the access was forced */ if( p_sys->fd_video < 0 && p_sys->fd_audio < 0 ) { if( !p_input->psz_access || strcmp( p_input->psz_access, "v4l" ) ) { AccessClose( p_this ); return VLC_EGENERIC; } } /* Find video device */ if( p_sys->fd_video < 0 ) { if( !p_sys->psz_vdev || !*p_sys->psz_vdev ) { var_Create( p_input, "v4l-vdev", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_input, "v4l-vdev", &val ); if( p_sys->psz_vdev ) free( p_sys->psz_vdev ); p_sys->psz_vdev = val.psz_string; } if( p_sys->psz_vdev && *p_sys->psz_vdev ) { p_sys->fd_video = OpenVideoDev( p_input, p_sys->psz_vdev ); } } /* Find audio device */ if( p_sys->fd_audio < 0 ) { if( !p_sys->psz_adev || !*p_sys->psz_adev ) { var_Create( p_input, "v4l-adev", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_input, "v4l-adev", &val ); if( p_sys->psz_adev ) free( p_sys->psz_adev ); p_sys->psz_adev = val.psz_string; } if( p_sys->psz_adev && *p_sys->psz_adev ) { p_sys->fd_audio = OpenAudioDev( p_input, p_sys->psz_adev ); } } if( p_sys->fd_video < 0 && p_sys->fd_audio < 0 ) { AccessClose( p_this ); return VLC_EGENERIC; } p_input->pf_read = Read; p_input->pf_seek = NULL; p_input->pf_set_area = NULL; p_input->pf_set_program = NULL; vlc_mutex_lock( &p_input->stream.stream_lock ); p_input->stream.b_pace_control = 0; p_input->stream.b_seekable = 0; p_input->stream.p_selected_area->i_size = 0; p_input->stream.p_selected_area->i_tell = 0; p_input->stream.i_method = INPUT_METHOD_FILE; vlc_mutex_unlock( &p_input->stream.stream_lock ); /* Update default_pts to a suitable value for access */ var_Create( p_input, "v4l-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Get( p_input, "v4l-caching", &val ); p_input->i_pts_delay = val.i_int * 1000; msg_Info( p_input, "v4l grabbing started" ); /* create header */ p_sys->i_streams = 0; p_sys->i_header_size = 8; p_sys->i_header_pos = 8; p_sys->p_header = malloc( p_sys->i_header_size );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -