📄 v4l.c
字号:
VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_demux, "v4l-samplerate", &val ); p_sys->i_sample_rate = val.i_int; var_Create( p_demux, "v4l-stereo", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_demux, "v4l-stereo", &val ); p_sys->b_stereo = val.b_bool; p_sys->psz_device = p_sys->psz_vdev = p_sys->psz_adev = NULL; p_sys->fd_video = -1; p_sys->fd_audio = -1; p_sys->p_es_video = p_sys->p_es_audio = 0; p_sys->p_block_audio = 0; ParseMRL( p_demux ); /* Find main device (video or audio) */ if( p_sys->psz_device && *p_sys->psz_device ) { msg_Dbg( p_demux, "main device=`%s'", p_sys->psz_device ); /* Try to open as video device */ p_sys->fd_video = OpenVideoDev( p_demux, p_sys->psz_device ); if( p_sys->fd_video < 0 ) { /* Try to open as audio device */ p_sys->fd_audio = OpenAudioDev( p_demux, p_sys->psz_device ); if( p_sys->fd_audio >= 0 ) { free( p_sys->psz_adev ); p_sys->psz_adev = p_sys->psz_device; p_sys->psz_device = NULL; } } else { 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( strcmp( p_demux->psz_access, "v4l" ) ) { Close( p_this ); return VLC_EGENERIC; } } /* Find video device */ if( p_sys->fd_video < 0 ) { if( !p_sys->psz_vdev || !*p_sys->psz_vdev ) { free( p_sys->psz_vdev ); p_sys->psz_vdev = var_CreateGetString( p_demux, "v4l-vdev" );; } if( p_sys->psz_vdev && *p_sys->psz_vdev ) { p_sys->fd_video = OpenVideoDev( p_demux, p_sys->psz_vdev ); } } /* Find audio device */ if( p_sys->fd_audio < 0 ) { if( !p_sys->psz_adev || !*p_sys->psz_adev ) { free( p_sys->psz_adev ); p_sys->psz_adev = var_CreateGetString( p_demux, "v4l-adev" );; } if( p_sys->psz_adev && *p_sys->psz_adev ) { p_sys->fd_audio = OpenAudioDev( p_demux, p_sys->psz_adev ); } } if( p_sys->fd_video < 0 && p_sys->fd_audio < 0 ) { Close( p_this ); return VLC_EGENERIC; } msg_Dbg( p_demux, "v4l grabbing started" ); /* Declare elementary streams */ if( p_sys->fd_video >= 0 ) { es_format_t fmt; es_format_Init( &fmt, VIDEO_ES, p_sys->i_fourcc ); fmt.video.i_width = p_sys->i_width; fmt.video.i_height = p_sys->i_height; fmt.video.i_aspect = 4 * VOUT_ASPECT_FACTOR / 3; /* Setup rgb mask for RGB formats */ switch( p_sys->i_fourcc ) { case VLC_FOURCC('R','V','1','5'): fmt.video.i_rmask = 0x001f; fmt.video.i_gmask = 0x03e0; fmt.video.i_bmask = 0x7c00; break; case VLC_FOURCC('R','V','1','6'): fmt.video.i_rmask = 0x001f; fmt.video.i_gmask = 0x07e0; fmt.video.i_bmask = 0xf800; break; case VLC_FOURCC('R','V','2','4'): case VLC_FOURCC('R','V','3','2'): fmt.video.i_rmask = 0x00ff0000; fmt.video.i_gmask = 0x0000ff00; fmt.video.i_bmask = 0x000000ff; break; } msg_Dbg( p_demux, "added new video es %4.4s %dx%d", (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height ); p_sys->p_es_video = es_out_Add( p_demux->out, &fmt ); } if( p_sys->fd_audio >= 0 ) { es_format_t fmt; es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC('a','r','a','w') ); fmt.audio.i_channels = p_sys->b_stereo ? 2 : 1; fmt.audio.i_rate = p_sys->i_sample_rate; fmt.audio.i_bitspersample = 16; // FIXME ? fmt.audio.i_blockalign = fmt.audio.i_channels * fmt.audio.i_bitspersample / 8; fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate * fmt.audio.i_bitspersample; msg_Dbg( p_demux, "new audio es %d channels %dHz", fmt.audio.i_channels, fmt.audio.i_rate ); p_sys->p_es_audio = es_out_Add( p_demux->out, &fmt ); } /* Update default_pts to a suitable value for access */ var_Create( p_demux, "v4l-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); return VLC_SUCCESS;}/***************************************************************************** * Close: close device, free resources *****************************************************************************/static void Close( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t *)p_this; demux_sys_t *p_sys = p_demux->p_sys; free( p_sys->psz_device ); free( p_sys->psz_vdev ); free( p_sys->psz_adev ); if( p_sys->fd_video >= 0 ) close( p_sys->fd_video ); if( p_sys->fd_audio >= 0 ) close( p_sys->fd_audio ); if( p_sys->p_block_audio ) block_Release( p_sys->p_block_audio ); if( p_sys->b_mjpeg ) { int i_noframe = -1; ioctl( p_sys->fd_video, MJPIOC_QBUF_CAPT, &i_noframe ); } if( p_sys->p_video_mmap && p_sys->p_video_mmap != MAP_FAILED ) { if( p_sys->b_mjpeg ) munmap( p_sys->p_video_mmap, p_sys->mjpeg_buffers.size * p_sys->mjpeg_buffers.count ); else munmap( p_sys->p_video_mmap, p_sys->vid_mbuf.size ); } free( p_sys );}/***************************************************************************** * Control: *****************************************************************************/static int Control( demux_t *p_demux, int i_query, va_list args ){ bool *pb; int64_t *pi64; switch( i_query ) { /* Special for access_demux */ case DEMUX_CAN_PAUSE: case DEMUX_CAN_SEEK: case DEMUX_SET_PAUSE_STATE: case DEMUX_CAN_CONTROL_PACE: pb = (bool*)va_arg( args, bool * ); *pb = false; return VLC_SUCCESS; case DEMUX_GET_PTS_DELAY: pi64 = (int64_t*)va_arg( args, int64_t * ); *pi64 = (int64_t)var_GetInteger( p_demux, "v4l-caching" ) * 1000; return VLC_SUCCESS; case DEMUX_GET_TIME: pi64 = (int64_t*)va_arg( args, int64_t * ); *pi64 = mdate(); return VLC_SUCCESS; /* TODO implement others */ default: return VLC_EGENERIC; } return VLC_EGENERIC;}/***************************************************************************** * Demux: *****************************************************************************/static int Demux( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; es_out_id_t *p_es = p_sys->p_es_audio; block_t *p_block = NULL; /* Try grabbing audio frames first */ if( p_sys->fd_audio < 0 || !( p_block = GrabAudio( p_demux ) ) ) { /* Try grabbing video frame */ p_es = p_sys->p_es_video; if( p_sys->fd_video > 0 ) p_block = GrabVideo( p_demux ); } if( !p_block ) { /* Sleep so we do not consume all the cpu, 10ms seems * like a good value (100fps) */ msleep( 10000 ); return 1; } es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts ); es_out_Send( p_demux->out, p_es, p_block ); return 1;}/***************************************************************************** * ParseMRL: parse the options contained in the MRL *****************************************************************************/static void ParseMRL( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; char *psz_dup = strdup( p_demux->psz_path ); char *psz_parser = psz_dup; while( *psz_parser && *psz_parser != ':' ) { psz_parser++; } if( *psz_parser == ':' ) { /* read options */ for( ;; ) { *psz_parser++ = '\0'; if( !strncmp( psz_parser, "channel=", strlen( "channel=" ) ) ) { p_sys->i_channel = strtol( psz_parser + strlen( "channel=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "norm=", strlen( "norm=" ) ) ) { psz_parser += strlen( "norm=" ); if( !strncmp( psz_parser, "pal", strlen( "pal" ) ) ) { p_sys->i_norm = VIDEO_MODE_PAL; psz_parser += strlen( "pal" ); } else if( !strncmp( psz_parser, "ntsc", strlen( "ntsc" ) ) ) { p_sys->i_norm = VIDEO_MODE_NTSC; psz_parser += strlen( "ntsc" ); } else if( !strncmp( psz_parser, "secam", strlen( "secam" ) ) ) { p_sys->i_norm = VIDEO_MODE_SECAM; psz_parser += strlen( "secam" ); } else if( !strncmp( psz_parser, "auto", strlen( "auto" ) ) ) { p_sys->i_norm = VIDEO_MODE_AUTO; psz_parser += strlen( "auto" ); } else { p_sys->i_norm = strtol( psz_parser, &psz_parser, 0 ); } } else if( !strncmp( psz_parser, "frequency=", strlen( "frequency=" ) ) ) { p_sys->i_frequency = strtol( psz_parser + strlen( "frequency=" ), &psz_parser, 0 ); if( p_sys->i_frequency < 30000 ) { msg_Warn( p_demux, "v4l syntax has changed : " "'frequency' is now channel frequency in kHz"); } } else if( !strncmp( psz_parser, "audio=", strlen( "audio=" ) ) ) { p_sys->i_audio = strtol( psz_parser + strlen( "audio=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "size=", strlen( "size=" ) ) ) { psz_parser += strlen( "size=" ); if( !strncmp( psz_parser, "subqcif", strlen( "subqcif" ) ) ) { p_sys->i_width = 128; p_sys->i_height = 96; } else if( !strncmp( psz_parser, "qsif", strlen( "qsif" ) ) ) { p_sys->i_width = 160; p_sys->i_height = 120; } else if( !strncmp( psz_parser, "qcif", strlen( "qcif" ) ) ) { p_sys->i_width = 176; p_sys->i_height = 144; } else if( !strncmp( psz_parser, "sif", strlen( "sif" ) ) ) { p_sys->i_width = 320; p_sys->i_height = 244; } else if( !strncmp( psz_parser, "cif", strlen( "cif" ) ) ) { p_sys->i_width = 352; p_sys->i_height = 288; } else if( !strncmp( psz_parser, "vga", strlen( "vga" ) ) ) { p_sys->i_width = 640; p_sys->i_height = 480; } else { /* widthxheight */ p_sys->i_width = strtol( psz_parser, &psz_parser, 0 ); if( *psz_parser == 'x' || *psz_parser == 'X') { p_sys->i_height = strtol( psz_parser + 1, &psz_parser, 0 ); } msg_Dbg( p_demux, "WxH %dx%d", p_sys->i_width, p_sys->i_height ); } } else if( !strncmp( psz_parser, "brightness=", strlen( "brightness=" ) ) ) { p_sys->i_brightness = strtol( psz_parser + strlen( "brightness=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "colour=", strlen( "colour=" ) ) ) { p_sys->i_colour = strtol( psz_parser + strlen( "colour=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "hue=", strlen( "hue=" ) ) ) { p_sys->i_hue = strtol( psz_parser + strlen( "hue=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "contrast=", strlen( "contrast=" ) ) ) { p_sys->i_contrast = strtol( psz_parser + strlen( "contrast=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "tuner=", strlen( "tuner=" ) ) ) { p_sys->i_tuner = strtol( psz_parser + strlen( "tuner=" ), &psz_parser, 0 ); } else if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) ) ) { int i_len; psz_parser += strlen( "adev=" ); if( strchr( psz_parser, ':' ) ) { i_len = strchr( psz_parser, ':' ) - psz_parser;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -