1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-18 17:40:30 +00:00

Teletext support

Part 3/5: grabbing raw VBI data



git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@23921 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
voroshil 2007-07-29 17:56:47 +00:00
parent 4f0d56b9ae
commit 0c9c146505

View File

@ -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;