📄 v4l2.c
字号:
} } /* Free Video Buffers */ if( p_sys->p_buffers ) { switch( p_sys->io ) { case IO_METHOD_READ: free( p_sys->p_buffers[0].start ); break; case IO_METHOD_MMAP: for( i = 0; i < p_sys->i_nbuffers; ++i ) { if( v4l2_munmap( p_sys->p_buffers[i].start, p_sys->p_buffers[i].length ) ) { msg_Err( p_this, "munmap failed" ); } } break; case IO_METHOD_USERPTR: for( i = 0; i < p_sys->i_nbuffers; ++i ) { free( p_sys->p_buffers[i].start ); } break; } free( p_sys->p_buffers ); } CommonClose( p_this, p_sys );}static void CommonClose( vlc_object_t *p_this, demux_sys_t *p_sys ){ (void)p_this; /* Close */ if( p_sys->i_fd_video >= 0 ) v4l2_close( p_sys->i_fd_video );#ifdef HAVE_ALSA if( p_sys->p_alsa_pcm ) { snd_pcm_close( p_sys->p_alsa_pcm ); p_sys->i_fd_audio = -1; }#endif if( p_sys->i_fd_audio >= 0 ) close( p_sys->i_fd_audio ); if( p_sys->p_block_audio ) block_Release( p_sys->p_block_audio ); free( p_sys->psz_device ); free( p_sys->psz_vdev ); free( p_sys->psz_adev ); free( p_sys->p_standards ); free( p_sys->p_inputs ); free( p_sys->p_tuners ); free( p_sys->p_codecs ); free( p_sys->psz_requested_chroma ); free( p_sys->psz_set_ctrls ); free( p_sys );}/***************************************************************************** * AccessOpen: opens v4l2 device, access callback ***************************************************************************** * * url: <video device>:::: * *****************************************************************************/static int AccessOpen( vlc_object_t * p_this ){ access_t *p_access = (access_t*) p_this; demux_sys_t * p_sys; /* Only when selected */ if( *p_access->psz_access == '\0' ) return VLC_EGENERIC; p_access->pf_read = AccessRead; p_access->pf_block = NULL; p_access->pf_seek = NULL; p_access->pf_control = AccessControl; p_access->info.i_update = 0; p_access->info.i_size = 0; p_access->info.i_pos = 0; p_access->info.b_eof = false; p_access->info.i_title = 0; p_access->info.i_seekpoint = 0; p_sys = calloc( 1, sizeof( demux_sys_t ) ); p_access->p_sys = (access_sys_t *) p_sys; if( p_sys == NULL ) return VLC_ENOMEM; GetV4L2Params( p_sys, (vlc_object_t *) p_access ); ParseMRL( p_sys, p_access->psz_path, (vlc_object_t *) p_access ); if( FindMainDevice( p_this, p_sys, FIND_VIDEO, false, !strncmp( p_access->psz_access, "v4l2", 4 ) ) != VLC_SUCCESS ) { AccessClose( p_this ); return VLC_EGENERIC; } return VLC_SUCCESS;}/***************************************************************************** * DemuxControl: *****************************************************************************/static int DemuxControl( demux_t *p_demux, int i_query, va_list args ){ demux_sys_t *p_sys = p_demux->p_sys; 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)p_sys->i_pts * 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;}/***************************************************************************** * AccessControl: access callback *****************************************************************************/static int AccessControl( access_t *p_access, int i_query, va_list args ){ bool *pb_bool; int *pi_int; int64_t *pi_64; demux_sys_t *p_sys = (demux_sys_t *) p_access->p_sys; switch( i_query ) { /* */ case ACCESS_CAN_SEEK: case ACCESS_CAN_FASTSEEK: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = false; break; case ACCESS_CAN_PAUSE: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = false; break; case ACCESS_CAN_CONTROL_PACE: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = false; break; /* */ case ACCESS_GET_MTU: pi_int = (int*)va_arg( args, int * ); *pi_int = 0; break; case ACCESS_GET_PTS_DELAY: pi_64 = (int64_t*)va_arg( args, int64_t * ); *pi_64 = (int64_t) p_sys->i_pts * 1000; break; /* */ case ACCESS_SET_PAUSE_STATE: /* Nothing to do */ break; case ACCESS_GET_TITLE_INFO: case ACCESS_SET_TITLE: case ACCESS_SET_SEEKPOINT: case ACCESS_SET_PRIVATE_ID_STATE: case ACCESS_GET_CONTENT_TYPE: case ACCESS_GET_META: return VLC_EGENERIC; default: msg_Warn( p_access, "Unimplemented query in control(%d).", i_query); return VLC_EGENERIC; } return VLC_SUCCESS;}/***************************************************************************** * AccessRead: access callback ******************************************************************************/static ssize_t AccessRead( access_t * p_access, uint8_t * p_buffer, size_t i_len ){ demux_sys_t *p_sys = (demux_sys_t *) p_access->p_sys; struct pollfd ufd; int i_ret; ufd.fd = p_sys->i_fd_video; ufd.events = POLLIN; if( p_access->info.b_eof ) return 0; do { if( !vlc_object_alive (p_access) ) return 0; ufd.revents = 0; } while( ( i_ret = poll( &ufd, 1, 500 ) ) == 0 ); if( i_ret < 0 ) { msg_Err( p_access, "Polling error (%m)." ); return -1; } i_ret = v4l2_read( p_sys->i_fd_video, p_buffer, i_len ); if( i_ret == 0 ) { p_access->info.b_eof = true; } else if( i_ret > 0 ) { p_access->info.i_pos += i_ret; } return i_ret;}/***************************************************************************** * Demux: Processes the audio or video frame *****************************************************************************/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->i_fd_audio < 0 || !( p_block = GrabAudio( p_demux ) ) ) { /* Try grabbing video frame */ p_es = p_sys->p_es_video; if( p_sys->i_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) */ /* Yeah, nevermind this was sleeping 10 microseconds! This is * completely brain damaged anyway. Use poll() or mwait() FIXME. */ 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;}/***************************************************************************** * GrabVideo: Grab a video frame *****************************************************************************/static block_t* GrabVideo( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block = NULL; struct v4l2_buffer buf; ssize_t i_ret; if( p_sys->f_fps >= 0.1 && p_sys->i_video_pts > 0 ) { mtime_t i_dur = (mtime_t)((double)1000000 / (double)p_sys->f_fps); /* Did we wait long enough ? (frame rate reduction) */ if( p_sys->i_video_pts + i_dur > mdate() ) return 0; } /* Grab Video Frame */ switch( p_sys->io ) { case IO_METHOD_READ: i_ret = v4l2_read( p_sys->i_fd_video, p_sys->p_buffers[0].start, p_sys->p_buffers[0].length ); if( i_ret == -1 ) { switch( errno ) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: msg_Err( p_demux, "Failed to read frame" ); return 0; } } p_block = ProcessVideoFrame( p_demux, (uint8_t*)p_sys->p_buffers[0].start, i_ret ); if( !p_block ) return 0; break; case IO_METHOD_MMAP: memset( &buf, 0, sizeof(buf) ); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; /* Wait for next frame */ if (v4l2_ioctl( p_sys->i_fd_video, VIDIOC_DQBUF, &buf ) < 0 ) { switch( errno ) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: msg_Err( p_demux, "Failed to wait (VIDIOC_DQBUF)" ); return 0; } } if( buf.index >= p_sys->i_nbuffers ) { msg_Err( p_demux, "Failed capturing new frame as i>=nbuffers" ); return 0; } p_block = ProcessVideoFrame( p_demux, p_sys->p_buffers[buf.index].start, 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; case IO_METHOD_USERPTR: memset( &buf, 0, sizeof(buf) ); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; /* Wait for next frame */ if (v4l2_ioctl( p_sys->i_fd_video, VIDIOC_DQBUF, &buf ) < 0 ) { switch( errno ) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -