📄 tvi_v4l.c
字号:
bufsize = priv->tv_param->buffer_size*1024*1024; } else {#ifdef HAVE_SYS_SYSINFO_H struct sysinfo si; sysinfo(&si); if (si.totalram<2*1024*1024) { bufsize = 1024*1024; } else { bufsize = si.totalram/2; }#else bufsize = 16*1024*1024;#endif } cnt = bufsize/(priv->height*priv->bytesperline); if (cnt < 2) cnt = 2; return cnt;}#ifdef HAVE_TV_TELETEXTstatic int vbi_init(priv_t* priv,char* device){ int vbi_fd=0; struct video_capability cap; if(!device) return TVI_CONTROL_FALSE; priv->vbi_dev=strdup(device); vbi_fd=open(priv->vbi_dev,O_RDWR); if(vbi_fd<0){ mp_msg(MSGT_TV,MSGL_ERR,"vbi: could not open device %s\n",priv->vbi_dev); return TVI_CONTROL_FALSE; } if(ioctl(vbi_fd,VIDIOCGCAP,&cap)<0){ mp_msg(MSGT_TV,MSGL_ERR,"vbi: Query capatibilities failed for %s\n",priv->vbi_dev); close(vbi_fd); return TVI_CONTROL_FALSE; } if(!cap.type & VID_TYPE_CAPTURE){ mp_msg(MSGT_TV,MSGL_ERR,"vbi: %s is not capture device\n",priv->vbi_dev); close(vbi_fd); return TVI_CONTROL_FALSE; } priv->vbi_fd=vbi_fd; mp_msg(MSGT_TV,MSGL_DBG3,"vbi: init ok\n"); return TVI_CONTROL_TRUE;}static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp){ struct vbi_format fmt; int res; if(!priv || !ptsp) return TVI_CONTROL_FALSE; memset(&fmt,0,sizeof(struct vbi_format)); if((res=ioctl(priv->vbi_fd,VIDIOCGVBIFMT,&fmt))<0){ mp_msg(MSGT_TV,MSGL_ERR,"vbi_get_props: Query format failed: %x\n",res); return TVI_CONTROL_FALSE; } ptsp->interlaced=(fmt.flags& VBI_INTERLACED?1:0); if(fmt.start[1]>0 && fmt.count[1]){ if(fmt.start[1]>=286) //625 ptsp->offset=10.2e-6*fmt.sampling_rate; else //525 ptsp->offset=9.2e-6*fmt.sampling_rate; }else ptsp->offset=9.7e-6*fmt.sampling_rate; ptsp->sampling_rate=fmt.sampling_rate; ptsp->samples_per_line=fmt.samples_per_line, ptsp->count[0]=fmt.count[0]; ptsp->count[1]=fmt.count[1]; ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]); mp_msg(MSGT_TV,MSGL_V,"vbi_get_props: sampling_rate=%d,offset:%d,samples_per_line: %d\n interlaced:%s, count=[%d,%d]\n", ptsp->sampling_rate, ptsp->offset, ptsp->samples_per_line, ptsp->interlaced?"Yes":"No", ptsp->count[0], ptsp->count[1]); return TVI_CONTROL_TRUE;}static void *vbi_grabber(void *data){ priv_t *priv = (priv_t *) data; int bytes,seq,prev_seq; unsigned char* buf; tt_stream_props tsp; if(!priv->priv_vbi){ mp_msg(MSGT_TV,MSGL_WARN,"vbi: vbi not initialized. stopping thread.\n"); return NULL; } if(vbi_get_props(priv,&tsp)!=TVI_CONTROL_TRUE) return NULL; buf=malloc(tsp.bufsize); seq=0; prev_seq=0; mp_msg(MSGT_TV,MSGL_V,"vbi: vbi capture thread started.\n"); while (!priv->vbi_shutdown){ bytes=read(priv->vbi_fd,buf,tsp.bufsize); if (bytes!=tsp.bufsize){ mp_msg(MSGT_TV,MSGL_WARN,"vbi: expecting bytes: %d, got: %d",tsp.bufsize,bytes); break; } seq=*(int*)(buf+bytes-4); if(seq<=1) continue; if (prev_seq && seq!=prev_seq+1){ prev_seq=0; seq=0; } prev_seq=seq; teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf); mp_msg(MSGT_TV,MSGL_DBG3,"grabber: seq:%d\n",seq); } free(buf); return NULL;}#endif //HAVE_TV_TELETEXTstatic int start(priv_t *priv){ int i; int bytes_per_sample; struct video_window win; if (ioctl(priv->video_fd, VIDIOCGPICT, &priv->picture) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); return(0); } priv->picture.palette = format2palette(priv->format); priv->picture.depth = palette2depth(priv->picture.palette); if (priv->format != IMGFMT_BGR15) { priv->bytesperline = priv->width * priv->picture.depth / 8; } else { priv->bytesperline = priv->width * 2; } mp_msg(MSGT_TV, MSGL_V, "Picture values:\n"); mp_msg(MSGT_TV, MSGL_V, " Depth: %d, Palette: %s (Format: %s)\n", priv->picture.depth, PALETTE(priv->picture.palette), vo_format_name(priv->format)); mp_msg(MSGT_TV, MSGL_V, " Brightness: %d, Hue: %d, Colour: %d, Contrast: %d\n", priv->picture.brightness, priv->picture.hue, priv->picture.colour, priv->picture.contrast); if (ioctl(priv->video_fd, VIDIOCSPICT, &priv->picture) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "ioctl set picture failed: %s\n", strerror(errno)); mp_msg(MSGT_TV, MSGL_ERR, "The 'outfmt' of '%s' is likely not supported by your card\n", vo_format_name(priv->format)); return 0; } /* Set capture size */ win.x = 0; win.y = 0; win.width = priv->width; win.height = priv->height; win.chromakey = -1; win.flags = 0; win.clipcount = 0; if (ioctl(priv->video_fd, VIDIOCSWIN, &win) == -1) mp_msg(MSGT_TV, MSGL_ERR, "ioctl set window failed: %s\n", strerror(errno)); if ( !priv->tv_param->mjpeg ) { /* map grab buffer */ if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "ioctl get mbuf failed: %s\n", strerror(errno)); return 0; } mp_msg(MSGT_TV, MSGL_V, "mbuf: size=%d, frames=%d\n", priv->mbuf.size, priv->mbuf.frames); priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, priv->video_fd, 0); if (priv->mmap == (unsigned char *)-1) { mp_msg(MSGT_TV, MSGL_ERR, "Unable to map memory for buffers: %s\n", strerror(errno)); return 0; } mp_msg(MSGT_TV, MSGL_DBG2, "our buffer: %p\n", priv->mmap); /* num of buffers */ priv->nbuf = priv->mbuf.frames; /* video buffers */ priv->buf = calloc(priv->nbuf, sizeof(struct video_mmap)); if (!priv->buf) return 0; memset(priv->buf, 0, priv->nbuf * sizeof(struct video_mmap)); } if ( !priv->tv_param->mjpeg ) { priv->nbuf = priv->mbuf.frames; for (i=0; i < priv->nbuf; i++) { priv->buf[i].format = priv->picture.palette; priv->buf[i].frame = i; priv->buf[i].width = priv->width; priv->buf[i].height = priv->height; mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]); } }#if 0 { struct video_play_mode pmode; pmode.mode = VID_PLAY_NORMAL; pmode.p1 = 1; pmode.p2 = 0; if (ioctl(priv->video_fd, VIDIOCSPLAYMODE, &pmode) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "ioctl set play mode failed: %s\n", strerror(errno));// return(0); } }#endif#if 0 // initialize video capture if (ioctl(priv->video_fd, VIDIOCCAPTURE, &one) == -1) { mp_msg(MSGT_TV, MSGL_ERR, "FATAL: ioctl ccapture failed: %s\n", strerror(errno)); return(0); }#endif /* setup audio parameters */ if (!priv->tv_param->noaudio) { setup_audio_buffer_sizes(priv); bytes_per_sample = priv->audio_in.bytes_per_sample; priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); if (!priv->audio_skew_buffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); return 0; } priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); if (!priv->audio_ringbuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); return 0; } priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate *priv->audio_in.channels *bytes_per_sample); priv->audio_head = 0; priv->audio_tail = 0; priv->audio_cnt = 0; priv->audio_drop = 0; priv->audio_skew = 0; priv->audio_skew_total = 0; priv->audio_recv_blocks_total = 0; priv->audio_sent_blocks_total = 0; } /* setup video parameters */ if (priv->immediate_mode) { priv->video_buffer_size_max = VID_BUF_SIZE_IMMEDIATE; } else { priv->video_buffer_size_max = get_capture_buffer_size(priv); } priv->video_buffer_size_current = 0; if (!priv->tv_param->noaudio) { if (priv->video_buffer_size_max < 3.0*priv->fps*priv->audio_secs_per_block) { mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" "You will probably experience heavy framedrops.\n"); } } mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", priv->video_buffer_size_max, priv->video_buffer_size_max*priv->height*priv->bytesperline/(1024*1024)); priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(unsigned char*)); if (!priv->video_ringbuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); return 0; } for (i = 0; i < priv->video_buffer_size_max; i++) priv->video_ringbuffer[i] = NULL; priv->video_timebuffer = calloc(priv->video_buffer_size_max, sizeof(long long)); if (!priv->video_timebuffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); return 0; } priv->video_avg_buffer = malloc(sizeof(long long) * VIDEO_AVG_BUFFER_SIZE); if (!priv->video_avg_buffer) { mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate period buffer: %s\n", strerror(errno)); return 0; } priv->video_interval_sum = (1e6/priv->fps)*VIDEO_AVG_BUFFER_SIZE; for (i = 0; i < VIDEO_AVG_BUFFER_SIZE; i++) { priv->video_avg_buffer[i] = 1e6/priv->fps; } priv->video_avg_ptr = 0; priv->video_head = 0; priv->video_tail = 0; priv->video_cnt = 0; priv->first = 1; if (priv->capability.audios) { /* enable audio */ if (priv->tv_param->volume >= 0) priv->audio[priv->audio_id].volume = priv->tv_param->volume; if (priv->tv_param->bass >= 0) priv->audio[priv->audio_id].bass = priv->tv_param->bass; if (priv->tv_param->treble >= 0) priv->audio[priv->audio_id].treble = priv->tv_param->treble; if (priv->tv_param->balance >= 0) priv->audio[priv->audio_id].balance = priv->tv_param->balance; priv->audio[priv->audio_id].flags &= ~VIDEO_AUDIO_MUTE; mp_msg(MSGT_TV, MSGL_V, "Enabling tv audio. Requested setup is:\n"); mp_msg(MSGT_TV, MSGL_V, "id=%d vol=%d bass=%d treble=%d balance=%d mode=%s", priv->audio_id, priv->audio[priv->audio_id].volume, priv->audio[priv->audio_id].bass, priv->audio[priv->audio_id].treble, priv->audio[priv->audio_id].balance, audio_mode2name(priv->audio[priv->audio_id].mode)); mp_msg(MSGT_TV, MSGL_V, " chan=%d\n", priv->audio_channels[priv->audio_id]); ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); }#ifdef HAVE_TV_TELETEXT /* start vbi thread */ if(priv->priv_vbi){ priv->vbi_shutdown = 0; pthread_create(&priv->vbi_grabber_thread, NULL, vbi_grabber, priv); }#endif /* launch capture threads */ priv->shutdown = 0; if (!priv->tv_param->noaudio) { pthread_mutex_init(&priv->audio_starter, NULL); pthread_mutex_init(&priv->skew_mutex, NULL); pthread_mutex_lock(&priv->audio_starter); pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); } pthread_mutex_init(&priv->video_buffer_mutex, NULL); /* we'll launch the video capture later, when a first request for a frame arrives */ return(1);}static int control(priv_t *priv, int cmd, void *arg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -