📄 v4l.c
字号:
{ p_sys->vid_picture = vid_picture; } else { /* Try to set the format to something easy to encode */ vid_picture.palette = VIDEO_PALETTE_YUV420P; if( ioctl( i_fd, VIDIOCSPICT, &vid_picture ) == 0 ) { p_sys->vid_picture = vid_picture; } else { vid_picture.palette = VIDEO_PALETTE_YUV422P; if( ioctl( i_fd, VIDIOCSPICT, &vid_picture ) == 0 ) { p_sys->vid_picture = vid_picture; } } } /* Find out final format */ for( i = 0; v4lchroma_to_fourcc[i].i_v4l != 0; i++ ) { if( v4lchroma_to_fourcc[i].i_v4l == p_sys->vid_picture.palette) { p_sys->i_fourcc = v4lchroma_to_fourcc[i].i_fourcc; break; } } } else { msg_Err( p_demux, "ioctl VIDIOCGPICT failed" ); goto vdev_failed; } } if( p_sys->b_mjpeg ) { int i; p_sys->mjpeg_buffers.count = 8; p_sys->mjpeg_buffers.size = MJPEG_BUFFER_SIZE; if( ioctl( i_fd, MJPIOC_REQBUFS, &p_sys->mjpeg_buffers ) < 0 ) { msg_Err( p_demux, "mmap unsupported" ); goto vdev_failed; } p_sys->p_video_mmap = mmap( 0, p_sys->mjpeg_buffers.size * p_sys->mjpeg_buffers.count, PROT_READ | PROT_WRITE, MAP_SHARED, i_fd, 0 ); if( p_sys->p_video_mmap == MAP_FAILED ) { msg_Err( p_demux, "mmap failed" ); goto vdev_failed; } p_sys->i_fourcc = VLC_FOURCC( 'm','j','p','g' ); p_sys->i_frame_pos = -1; /* queue up all the frames */ for( i = 0; i < (int)p_sys->mjpeg_buffers.count; i++ ) { if( ioctl( i_fd, MJPIOC_QBUF_CAPT, &i ) < 0 ) { msg_Err( p_demux, "unable to queue frame" ); goto vdev_failed; } } } else { /* Fill in picture_t fields */ vout_InitPicture( VLC_OBJECT(p_demux), &p_sys->pic, p_sys->i_fourcc, p_sys->i_width, p_sys->i_height, p_sys->i_width * VOUT_ASPECT_FACTOR / p_sys->i_height ); if( !p_sys->pic.i_planes ) { msg_Err( p_demux, "unsupported chroma" ); goto vdev_failed; } p_sys->i_video_frame_size = 0; for( i = 0; i < p_sys->pic.i_planes; i++ ) { p_sys->i_video_frame_size += p_sys->pic.p[i].i_visible_lines * p_sys->pic.p[i].i_visible_pitch; } msg_Dbg( p_demux, "v4l device uses frame size: %i", p_sys->i_video_frame_size ); msg_Dbg( p_demux, "v4l device uses chroma: %4.4s", (char*)&p_sys->i_fourcc ); /* Allocate mmap buffer */ if( ioctl( i_fd, VIDIOCGMBUF, &p_sys->vid_mbuf ) < 0 ) { msg_Err( p_demux, "mmap unsupported" ); goto vdev_failed; } p_sys->p_video_mmap = mmap( 0, p_sys->vid_mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, i_fd, 0 ); if( p_sys->p_video_mmap == MAP_FAILED ) { /* FIXME -> normal read */ msg_Err( p_demux, "mmap failed" ); goto vdev_failed; } /* init grabbing */ p_sys->vid_mmap.frame = 0; p_sys->vid_mmap.width = p_sys->i_width; p_sys->vid_mmap.height = p_sys->i_height; p_sys->vid_mmap.format = p_sys->vid_picture.palette; if( ioctl( i_fd, VIDIOCMCAPTURE, &p_sys->vid_mmap ) < 0 ) { msg_Warn( p_demux, "%4.4s refused", (char*)&p_sys->i_fourcc ); msg_Err( p_demux, "chroma selection failed" ); goto vdev_failed; } } return i_fd;vdev_failed: if( i_fd >= 0 ) close( i_fd ); return -1;}/***************************************************************************** * OpenAudioDev: *****************************************************************************/static int OpenAudioDev( demux_t *p_demux, char *psz_device ){ demux_sys_t *p_sys = p_demux->p_sys; int i_fd, i_format; if( (i_fd = open( psz_device, O_RDONLY | O_NONBLOCK )) < 0 ) { msg_Err( p_demux, "cannot open audio device (%m)" ); goto adev_fail; } i_format = AFMT_S16_LE; if( ioctl( i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 || i_format != AFMT_S16_LE ) { msg_Err( p_demux, "cannot set audio format (16b little endian) " "(%m)" ); goto adev_fail; } if( ioctl( i_fd, SNDCTL_DSP_STEREO, &p_sys->b_stereo ) < 0 ) { msg_Err( p_demux, "cannot set audio channels count (%m)" ); goto adev_fail; } if( ioctl( i_fd, SNDCTL_DSP_SPEED, &p_sys->i_sample_rate ) < 0 ) { msg_Err( p_demux, "cannot set audio sample rate (%m)" ); goto adev_fail; } msg_Dbg( p_demux, "opened adev=`%s' %s %dHz", psz_device, p_sys->b_stereo ? "stereo" : "mono", p_sys->i_sample_rate ); p_sys->i_audio_max_frame_size = 6 * 1024; return i_fd; adev_fail: if( i_fd >= 0 ) close( i_fd ); return -1;}/***************************************************************************** * GrabAudio: grab audio *****************************************************************************/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, 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; i_read = read( p_sys->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( ioctl( p_sys->fd_audio, SNDCTL_DSP_GETISPACE, &buf_info ) == 0 ) { i_correct += buf_info.bytes; } 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;}/***************************************************************************** * GrabVideo: *****************************************************************************/static uint8_t *GrabCapture( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; int i_captured_frame = p_sys->i_frame_pos; p_sys->vid_mmap.frame = (p_sys->i_frame_pos + 1) % p_sys->vid_mbuf.frames; while( ioctl( p_sys->fd_video, VIDIOCMCAPTURE, &p_sys->vid_mmap ) < 0 ) { if( errno != EAGAIN ) { msg_Err( p_demux, "failed capturing new frame" ); return NULL; } if( !vlc_object_alive (p_demux) ) { return NULL; } msg_Dbg( p_demux, "grab failed, trying again" ); } while( ioctl(p_sys->fd_video, VIDIOCSYNC, &p_sys->i_frame_pos) < 0 ) { if( errno != EAGAIN && errno != EINTR ) { msg_Err( p_demux, "failed syncing new frame" ); return NULL; } } p_sys->i_frame_pos = p_sys->vid_mmap.frame; /* leave i_video_frame_size alone */ return p_sys->p_video_mmap + p_sys->vid_mbuf.offsets[i_captured_frame];}static uint8_t *GrabMJPEG( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; struct mjpeg_sync sync; uint8_t *p_frame, *p_field, *p; uint16_t tag; uint32_t i_size; struct quicktime_mjpeg_app1 *p_app1 = NULL; /* re-queue the last frame we sync'd */ if( p_sys->i_frame_pos != -1 ) { while( ioctl( p_sys->fd_video, MJPIOC_QBUF_CAPT, &p_sys->i_frame_pos ) < 0 ) { if( errno != EAGAIN && errno != EINTR ) { msg_Err( p_demux, "failed capturing new frame" ); return NULL; } } } /* sync on the next frame */ while( ioctl( p_sys->fd_video, MJPIOC_SYNC, &sync ) < 0 ) { if( errno != EAGAIN && errno != EINTR ) { msg_Err( p_demux, "failed syncing new frame" ); return NULL; } } p_sys->i_frame_pos = sync.frame; p_frame = p_sys->p_video_mmap + p_sys->mjpeg_buffers.size * sync.frame; /* p_frame now points to the data. fix up the Quicktime APP1 marker */ tag = 0xffd9; tag = hton16( tag ); p_field = p_frame; /* look for EOI */ p = memmem( p_field, sync.length, &tag, 2 ); if( p ) { p += 2; /* data immediately following EOI */ /* UNALIGNED! */ p_app1 = (struct quicktime_mjpeg_app1 *)(p_field + 6); i_size = ((uint32_t)(p - p_field)); i_size = hton32( i_size ); memcpy( &p_app1->i_field_size, &i_size, 4 ); while( *p == 0xff && *(p+1) == 0xff ) p++; i_size = ((uint32_t)(p - p_field)); i_size = hton32( i_size ); memcpy( &p_app1->i_padded_field_size, &i_size, 4 ); } tag = 0xffd8; tag = hton16( tag ); p_field = memmem( p, sync.length - (size_t)(p - p_frame), &tag, 2 ); if( p_field ) { i_size = (uint32_t)(p_field - p_frame); i_size = hton32( i_size ); memcpy( &p_app1->i_next_field, &i_size, 4 ); /* UNALIGNED! */ p_app1 = (struct quicktime_mjpeg_app1 *)(p_field + 6); tag = 0xffd9; tag = hton16( tag ); p = memmem( p_field, sync.length - (size_t)(p_field - p_frame), &tag, 2 ); if( !p ) { /* sometimes the second field doesn't have the EOI. just put it * there */ p = p_frame + sync.length; memcpy( p, &tag, 2 ); sync.length += 2; } p += 2; i_size = (uint32_t)(p - p_field); i_size = hton32( i_size ); memcpy( &p_app1->i_field_size, &i_size, 4 ); i_size = (uint32_t)(sync.length - (uint32_t)(p_field - p_frame)); i_size = hton32( i_size ); memcpy( &p_app1->i_padded_field_size, &i_size, 4 ); } p_sys->i_video_frame_size = sync.length; return p_frame;}static block_t *GrabVideo( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; uint8_t *p_frame; block_t *p_block; 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; } if( p_sys->b_mjpeg ) p_frame = GrabMJPEG( p_demux ); else p_frame = GrabCapture( p_demux ); if( !p_frame ) return 0; if( !( p_block = block_New( p_demux, p_sys->i_video_frame_size ) ) ) { msg_Warn( p_demux, "cannot get block" ); return 0; } memcpy( p_block->p_buffer, p_frame, p_sys->i_video_frame_size ); p_sys->i_video_pts = p_block->i_pts = p_block->i_dts = mdate(); return p_block;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -