📄 v4l2.c
字号:
default: msg_Err( p_demux, "Failed to wait (VIDIOC_DQBUF)" ); return 0; } } /* Find frame? */ unsigned int i; for( i = 0; i < p_sys->i_nbuffers; i++ ) { if( buf.m.userptr == (unsigned long)p_sys->p_buffers[i].start && buf.length == p_sys->p_buffers[i].length ) break; } if( i >= p_sys->i_nbuffers ) { msg_Err( p_demux, "Failed capturing new frame as i>=nbuffers" ); return 0; } p_block = ProcessVideoFrame( p_demux, (uint8_t*)buf.m.userptr, buf.bytesused ); if( !p_block ) return 0; /* Unlock */ if( v4l2_ioctl( p_sys->i_fd_video, VIDIOC_QBUF, &buf ) < 0 ) { msg_Err( p_demux, "Failed to unlock (VIDIOC_QBUF)" ); block_Release( p_block ); return 0; } break; } /* Timestamp */ p_sys->i_video_pts = p_block->i_pts = p_block->i_dts = mdate(); return p_block;}/***************************************************************************** * ProcessVideoFrame: Helper function to take a buffer and copy it into * a new block *****************************************************************************/static block_t* ProcessVideoFrame( demux_t *p_demux, uint8_t *p_frame, size_t i_size ){ block_t *p_block; if( !p_frame ) return 0; /* New block */ if( !( p_block = block_New( p_demux, i_size ) ) ) { msg_Warn( p_demux, "Cannot get new block" ); return 0; } /* Copy frame */ memcpy( p_block->p_buffer, p_frame, i_size ); return p_block;}/***************************************************************************** * GrabAudio: Grab an audio frame *****************************************************************************/static block_t* GrabAudio( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; struct audio_buf_info buf_info; int i_read = 0, i_correct; block_t *p_block; if( p_sys->p_block_audio ) p_block = p_sys->p_block_audio; else p_block = block_New( p_demux, p_sys->i_audio_max_frame_size ); if( !p_block ) { msg_Warn( p_demux, "cannot get block" ); return 0; } p_sys->p_block_audio = p_block;#ifdef HAVE_ALSA if( p_sys->i_audio_method & AUDIO_METHOD_ALSA ) { /* ALSA */ i_read = snd_pcm_readi( p_sys->p_alsa_pcm, p_block->p_buffer, p_sys->i_alsa_chunk_size ); if( i_read <= 0 ) { int i_resume; switch( i_read ) { case -EAGAIN: break; case -EPIPE: /* xrun */ snd_pcm_prepare( p_sys->p_alsa_pcm ); break; case -ESTRPIPE: /* suspend */ i_resume = snd_pcm_resume( p_sys->p_alsa_pcm ); if( i_resume < 0 && i_resume != -EAGAIN ) snd_pcm_prepare( p_sys->p_alsa_pcm ); break; default: msg_Err( p_demux, "Failed to read alsa frame (%s)", snd_strerror( i_read ) ); return 0; } } else { /* convert from frames to bytes */ i_read *= p_sys->i_alsa_frame_size; } } else#endif if( p_sys->i_audio_method & AUDIO_METHOD_OSS ) { /* OSS */ i_read = read( p_sys->i_fd_audio, p_block->p_buffer, p_sys->i_audio_max_frame_size ); } if( i_read <= 0 ) return 0; p_block->i_buffer = i_read; p_sys->p_block_audio = 0; /* Correct the date because of kernel buffering */ i_correct = i_read; if( p_sys->i_audio_method & AUDIO_METHOD_OSS ) { /* OSS */ if( ioctl( p_sys->i_fd_audio, SNDCTL_DSP_GETISPACE, &buf_info ) == 0 ) { i_correct += buf_info.bytes; } }#ifdef HAVE_ALSA else if( p_sys->i_audio_method & AUDIO_METHOD_ALSA ) { /* ALSA */ int i_err; snd_pcm_sframes_t delay = 0; if( ( i_err = snd_pcm_delay( p_sys->p_alsa_pcm, &delay ) ) >= 0 ) { size_t i_correction_delta = delay * p_sys->i_alsa_frame_size; /* Test for overrun */ if( i_correction_delta > p_sys->i_audio_max_frame_size ) { msg_Warn( p_demux, "ALSA read overrun (%zu > %zu)", i_correction_delta, p_sys->i_audio_max_frame_size ); i_correction_delta = p_sys->i_audio_max_frame_size; snd_pcm_prepare( p_sys->p_alsa_pcm ); } i_correct += i_correction_delta; } else { /* delay failed so reset */ msg_Warn( p_demux, "ALSA snd_pcm_delay failed (%s)", snd_strerror( i_err ) ); snd_pcm_prepare( p_sys->p_alsa_pcm ); } }#endif /* Timestamp */ p_block->i_pts = p_block->i_dts = mdate() - INT64_C(1000000) * (mtime_t)i_correct / 2 / ( p_sys->b_stereo ? 2 : 1) / p_sys->i_sample_rate; return p_block;}/***************************************************************************** * Helper function to initalise video IO using the Read method *****************************************************************************/static int InitRead( demux_t *p_demux, int i_fd, unsigned int i_buffer_size ){ demux_sys_t *p_sys = p_demux->p_sys; p_sys->p_buffers = calloc( 1, sizeof( *p_sys->p_buffers ) ); if( !p_sys->p_buffers ) goto open_failed; p_sys->p_buffers[0].length = i_buffer_size; p_sys->p_buffers[0].start = malloc( i_buffer_size ); if( !p_sys->p_buffers[0].start ) goto open_failed; return VLC_SUCCESS;open_failed: return VLC_EGENERIC;}/***************************************************************************** * Helper function to initalise video IO using the mmap method *****************************************************************************/static int InitMmap( demux_t *p_demux, int i_fd ){ demux_sys_t *p_sys = p_demux->p_sys; struct v4l2_requestbuffers req; memset( &req, 0, sizeof(req) ); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if( v4l2_ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 ) { msg_Err( p_demux, "device does not support mmap i/o" ); goto open_failed; } if( req.count < 2 ) { msg_Err( p_demux, "Insufficient buffer memory" ); goto open_failed; } p_sys->p_buffers = calloc( req.count, sizeof( *p_sys->p_buffers ) ); if( !p_sys->p_buffers ) { msg_Err( p_demux, "Out of memory" ); goto open_failed; } for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < req.count; ++p_sys->i_nbuffers ) { struct v4l2_buffer buf; memset( &buf, 0, sizeof(buf) ); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = p_sys->i_nbuffers; if( v4l2_ioctl( i_fd, VIDIOC_QUERYBUF, &buf ) < 0 ) { msg_Err( p_demux, "VIDIOC_QUERYBUF" ); goto open_failed; } p_sys->p_buffers[p_sys->i_nbuffers].length = buf.length; p_sys->p_buffers[p_sys->i_nbuffers].start = v4l2_mmap( NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, i_fd, buf.m.offset ); if( p_sys->p_buffers[p_sys->i_nbuffers].start == MAP_FAILED ) { msg_Err( p_demux, "mmap failed (%m)" ); goto open_failed; } } return VLC_SUCCESS;open_failed: return VLC_EGENERIC;}/***************************************************************************** * Helper function to initalise video IO using the userbuf method *****************************************************************************/static int InitUserP( demux_t *p_demux, int i_fd, unsigned int i_buffer_size ){ demux_sys_t *p_sys = p_demux->p_sys; struct v4l2_requestbuffers req; unsigned int i_page_size; i_page_size = sysconf(_SC_PAGESIZE); i_buffer_size = ( i_buffer_size + i_page_size - 1 ) & ~( i_page_size - 1); memset( &req, 0, sizeof(req) ); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_USERPTR; if( v4l2_ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 ) { msg_Err( p_demux, "device does not support user pointer i/o" ); return VLC_EGENERIC; } p_sys->p_buffers = calloc( 4, sizeof( *p_sys->p_buffers ) ); if( !p_sys->p_buffers ) goto open_failed; for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < 4; ++p_sys->i_nbuffers ) { p_sys->p_buffers[p_sys->i_nbuffers].length = i_buffer_size; if( posix_memalign( &p_sys->p_buffers[p_sys->i_nbuffers].start, /* boundary */ i_page_size, i_buffer_size ) ) goto open_failed; } return VLC_SUCCESS;open_failed: free( p_sys->p_buffers ); return VLC_EGENERIC;}/***************************************************************************** * IsPixelFormatSupported: returns true if the specified V4L2 pixel format is * in the array of supported formats returned by the driver *****************************************************************************/static bool IsPixelFormatSupported( demux_t *p_demux, unsigned int i_pixelformat ){ demux_sys_t *p_sys = p_demux->p_sys; for( int i_index = 0; i_index < p_sys->i_codec; i_index++ ) { if( p_sys->p_codecs[i_index].pixelformat == i_pixelformat ) return true; } return false;}/***************************************************************************** * OpenVideoDev: open and set up the video device and probe for capabilities *****************************************************************************/static int OpenVideoDev( vlc_object_t *p_obj, demux_sys_t *p_sys, bool b_demux ){ int i_fd; struct v4l2_cropcap cropcap; struct v4l2_crop crop; struct v4l2_format fmt; unsigned int i_min; enum v4l2_buf_type buf_type; char *psz_device = p_sys->psz_vdev; es_format_t es_fmt; int libv4l2_fd; if( ( i_fd = open( psz_device, O_RDWR ) ) < 0 ) { msg_Err( p_obj, "cannot open device (%m)" ); goto open_failed; } /* Note the v4l2_xxx functions are designed so that if they get passed an unknown fd, the will behave exactly as their regular xxx counterparts, so if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom cam format to normal formats conversion). Chances are big we will still fail then though, as normally v4l2_fd_open only fails if the device is not a v4l2 device. */ libv4l2_fd = v4l2_fd_open(i_fd, V4L2_ENABLE_ENUM_FMT_EMULATION); if (libv4l2_fd != -1) i_fd = libv4l2_fd; /* Tune the tuner */ if( p_sys->i_frequency >= 0 ) { if( p_sys->i_cur_tuner < 0 || p_sys->i_cur_tuner >= p_sys->i_tuner ) { msg_Err( p_obj, "invalid tuner %d.", p_sys->i_cur_tuner ); goto open_failed; } struct v4l2_frequency frequency; memset( &frequency, 0, sizeof( frequency ) ); frequency.tuner = p_sys->i_cur_tuner; frequency.type = p_sys->p_tuners[p_sys->i_cur_tuner].type; frequency.frequency = p_sys->i_frequency / 62.5; if( v4l2_ioctl( i_fd, VIDIOC_S_FREQUENCY, &frequency ) < 0 ) { msg_Err( p_obj, "cannot set tuner frequency (%m)" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -