From 0c9c1465058a5d43b83df0a1b046b799bb91f760 Mon Sep 17 00:00:00 2001 From: voroshil Date: Sun, 29 Jul 2007 17:56:47 +0000 Subject: Teletext support Part 3/5: grabbing raw VBI data git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@23921 b3059339-0415-0410-9bf9-f77b7e298cf2 --- stream/tvi_v4l2.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) (limited to 'stream') diff --git a/stream/tvi_v4l2.c b/stream/tvi_v4l2.c index baf5590e46..31fa1434da 100644 --- a/stream/tvi_v4l2.c +++ b/stream/tvi_v4l2.c @@ -77,6 +77,14 @@ typedef struct { /* video */ char *video_dev; int video_fd; +#ifdef HAVE_TV_TELETEXT + char *vbi_dev; + int vbi_fd; + int vbi_bufsize; + int vbi_shutdown; + pthread_t vbi_grabber_thread; + void *priv_vbi; +#endif int mp_format; struct v4l2_capability capability; struct v4l2_input input; @@ -551,6 +559,129 @@ static int get_control(priv_t *priv, struct v4l2_control *control, int val_signe return TVI_CONTROL_TRUE; } +#ifdef HAVE_TV_TELETEXT +static int vbi_init(priv_t* priv,char* device) +{ + int vbi_fd=0; + struct v4l2_capability cap; + struct v4l2_format fmt; + int res; + + 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,VIDIOC_QUERYCAP,&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.capabilities & V4L2_CAP_VBI_CAPTURE){ + mp_msg(MSGT_TV,MSGL_ERR,"vbi: %s does not support VBI capture\n",priv->vbi_dev); + close(vbi_fd); + return TVI_CONTROL_FALSE; + } + + memset(&fmt,0,sizeof(struct v4l2_format)); + fmt.type=V4L2_BUF_TYPE_VBI_CAPTURE; + if((res=ioctl(vbi_fd,VIDIOC_G_FMT,&fmt))<0){ + mp_msg(MSGT_TV,MSGL_ERR,"vbi: Query format failed: %x\n",res); + close(vbi_fd); + return TVI_CONTROL_FALSE; + } + if(fmt.fmt.vbi.sample_format!=V4L2_PIX_FMT_GREY){ + mp_msg(MSGT_TV,MSGL_ERR,"vbi: format 0x%x is not supported\n",fmt.fmt.vbi.sample_format); + 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 v4l2_format fmt; + int res; + if(!priv || !ptsp) + return TVI_CONTROL_FALSE; + + memset(&fmt,0,sizeof(struct v4l2_format)); + fmt.type=V4L2_BUF_TYPE_VBI_CAPTURE; + if((res=ioctl(priv->vbi_fd,VIDIOC_G_FMT,&fmt))<0){ + mp_msg(MSGT_TV,MSGL_ERR,"vbi_get_props: Query format failed: %x\n",res); + return TVI_CONTROL_FALSE; + } + + ptsp->interlaced=(fmt.fmt.vbi.flags& V4L2_VBI_INTERLACED?1:0); + + ptsp->offset=fmt.fmt.vbi.offset; + ptsp->sampling_rate=fmt.fmt.vbi.sampling_rate; + ptsp->samples_per_line=fmt.fmt.vbi.samples_per_line, + + ptsp->count[0]=fmt.fmt.vbi.count[0]; + ptsp->count[1]=fmt.fmt.vbi.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_TELETEXT + static int control(priv_t *priv, int cmd, void *arg) { struct v4l2_control control; @@ -819,6 +950,27 @@ static int control(priv_t *priv, int cmd, void *arg) if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE; // setup_audio_buffer_sizes(priv); return TVI_CONTROL_TRUE; +#ifdef HAVE_TV_TELETEXT + case TVI_CONTROL_VBI_INIT: + { + void* ptr; + tt_stream_props tsp; + + if (vbi_init(priv,*(char**)arg)!=TVI_CONTROL_TRUE) + return TVI_CONTROL_FALSE; + if(vbi_get_props(priv,&tsp)==TVI_CONTROL_TRUE) + { + ptr=&tsp; + if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==TVI_CONTROL_TRUE) + priv->priv_vbi=ptr; + else + priv->priv_vbi=NULL; + } + return TVI_CONTROL_TRUE; + } + default: + return teletext_control(priv->priv_vbi,cmd,arg); +#endif } mp_msg(MSGT_TV, MSGL_V, "%s: unknown control: %d\n", info.short_name, cmd); return(TVI_CONTROL_UNKNOWN); @@ -865,6 +1017,26 @@ static int uninit(priv_t *priv) { int i, frames, dropped = 0; +#ifdef HAVE_TV_TELETEXT + priv->vbi_shutdown=1; + if(priv->vbi_grabber_thread) + pthread_join(priv->vbi_grabber_thread, NULL); + + teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1); + priv->priv_vbi=NULL; + + if(priv->vbi_fd){ + close(priv->vbi_fd); + priv->vbi_fd=0; + } + + if(priv->vbi_dev){ + free(priv->vbi_dev); + priv->vbi_dev=0; + } + +#endif + priv->shutdown = 1; if(priv->video_grabber_thread) pthread_join(priv->video_grabber_thread, NULL); @@ -1301,6 +1473,13 @@ static int start(priv_t *priv) } } +#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 /* start audio thread */ priv->shutdown = 0; priv->audio_skew_measure_time = 0; -- cgit v1.2.3