changeset 23901:657236b9eacb

Teletext support Part 3/5: grabbing raw VBI data
author voroshil
date Sun, 29 Jul 2007 17:56:47 +0000
parents b5cc28c45d73
children 29f612207c95
files stream/tvi_v4l2.c
diffstat 1 files changed, 179 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/stream/tvi_v4l2.c	Sun Jul 29 17:55:28 2007 +0000
+++ b/stream/tvi_v4l2.c	Sun Jul 29 17:56:47 2007 +0000
@@ -77,6 +77,14 @@
     /* 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 @@
     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 @@
         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 @@
 {
     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 @@
         }
     }
 
+#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;