changeset 24105:9e71e0345c35

Automatic TV channels scanning ability for MPlayer. Code is based on patch from Otvos Attila oattila at chello dot hu
author voroshil
date Thu, 23 Aug 2007 16:09:30 +0000
parents b0a47d3bf2f3
children 93c73ce74baa
files DOCS/man/en/mplayer.1 DOCS/tech/slave.txt cfg-mplayer.h command.c input/input.c input/input.h stream/stream_tv.c stream/tv.c stream/tv.h stream/tvi_def.h stream/tvi_v4l.c stream/tvi_v4l2.c
diffstat 12 files changed, 187 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/man/en/mplayer.1	Thu Aug 23 14:20:31 2007 +0000
+++ b/DOCS/man/en/mplayer.1	Thu Aug 23 16:09:30 2007 +0000
@@ -1899,6 +1899,26 @@
 .RE
 .
 .TP
+.B \-tvscan <option1:option2:...> (TV and MPlayer only)
+This option tunes various parameters for TV channel scanner.
+MPlayer will also print value for "-tv channels=" option,
+including existing and just found channels.
+.sp 1
+Available suboptions are:
+.RSs
+.IPs autostart (default: not set)
+Begin channel scanning immediately after MPlayer startup.
+.IPs period=<0.1-2.0> (default: 0.5)
+Specify delay in seconds before switching to next channel.
+Lower values will cause faster scanning, but can detect
+inactive TV channels as active.
+.IPs threshold=<1-100> (default: 50)
+Threshold value (in percent) for signal strength, reported by device.
+Signal strength higher than this value will indicate that
+currently scanning channel is active.
+.RE
+.
+.TP
 .B \-user <username> (also see \-passwd) (network only)
 Specify username for HTTP authentication.
 .
--- a/DOCS/tech/slave.txt	Thu Aug 23 14:20:31 2007 +0000
+++ b/DOCS/tech/slave.txt	Thu Aug 23 16:09:30 2007 +0000
@@ -330,6 +330,9 @@
     -    - Delete last digit from page number. (Backspace emulation, works only
            in page number editing mode.)
 
+tv_start_scan
+    Start automatic tv channels scaning
+
 tv_step_channel <channel>
     Select next/previous TV channel.
 
--- a/cfg-mplayer.h	Thu Aug 23 14:20:31 2007 +0000
+++ b/cfg-mplayer.h	Thu Aug 23 16:09:30 2007 +0000
@@ -114,6 +114,14 @@
 	{NULL, NULL, 0, 0, 0, 0, NULL}
 };
 
+#ifdef USE_TV
+m_option_t tvscan_conf[]={
+	{"autostart", &stream_tv_defaults.scan, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"threshold", &stream_tv_defaults.scan_threshold, CONF_TYPE_INT, CONF_RANGE, 1, 100, NULL},
+	{"period", &stream_tv_defaults.scan_period, CONF_TYPE_FLOAT, CONF_RANGE, 0.1, 2.0, NULL},
+	{NULL, NULL, 0, 0, 0, 0, NULL}
+};
+#endif
 /*
  * CONF_TYPE_FUNC_FULL :
  * allows own implementations for passing the params
@@ -387,6 +395,11 @@
 	{"mouse-movements", &enable_mouse_movements, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL},
 	{"nomouse-movements", &enable_mouse_movements, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL},
 	{"doubleclick-time", &doubleclick_time, CONF_TYPE_INT, CONF_RANGE, 0, 1000, NULL},
+#ifdef USE_TV
+	{"tvscan", &tvscan_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+#else
+	{"tvscan", "MPlayer was compiled without TV interface support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
+#endif
 
 #define MAIN_CONF
 #include "cfg-common.h"
--- a/command.c	Thu Aug 23 14:20:31 2007 +0000
+++ b/command.c	Thu Aug 23 16:09:30 2007 +0000
@@ -2287,6 +2287,10 @@
 #endif
 
 #ifdef USE_TV
+	case MP_CMD_TV_START_SCAN:
+	    if (mpctx->file_format == DEMUXER_TYPE_TV)
+		tv_start_scan((tvi_handle_t *) (mpctx->demuxer->priv),1);
+	    break;
 	case MP_CMD_TV_SET_FREQ:
 	    if (mpctx->file_format == DEMUXER_TYPE_TV)
 		tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
--- a/input/input.c	Thu Aug 23 14:20:31 2007 +0000
+++ b/input/input.c	Thu Aug 23 16:09:30 2007 +0000
@@ -111,6 +111,7 @@
   { MP_CMD_GET_META_GENRE, "get_meta_genre", 0, { {-1,{0}} } },
   { MP_CMD_SWITCH_AUDIO, "switch_audio", 0, { { MP_CMD_ARG_INT,{-1} }, {-1,{0}} } },
 #ifdef USE_TV
+  { MP_CMD_TV_START_SCAN, "tv_start_scan", 0,  { {-1,{0}} }},
   { MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", 1,  { { MP_CMD_ARG_INT ,{0}}, {-1,{0}} }},
   { MP_CMD_TV_STEP_NORM, "tv_step_norm",0, { {-1,{0}} }  },
   { MP_CMD_TV_STEP_CHANNEL_LIST, "tv_step_chanlist", 0, { {-1,{0}} }  },
--- a/input/input.h	Thu Aug 23 14:20:31 2007 +0000
+++ b/input/input.h	Thu Aug 23 16:09:30 2007 +0000
@@ -98,6 +98,7 @@
 #define MP_CMD_SUB_SCALE 97
 #define MP_CMD_TV_TELETEXT_ADD_DEC 98
 #define MP_CMD_TV_TELETEXT_GO_LINK 99
+#define MP_CMD_TV_START_SCAN 100
 
 #define MP_CMD_GUI_EVENTS       5000
 #define MP_CMD_GUI_LOADFILE     5001
--- a/stream/stream_tv.c	Thu Aug 23 14:20:31 2007 +0000
+++ b/stream/stream_tv.c	Thu Aug 23 16:09:30 2007 +0000
@@ -74,7 +74,11 @@
     0,             //saturation
     NULL,          //tdevice
     0,             //tformat
-    100            //tpage
+    100,           //tpage
+
+    0,             //scan_autostart
+    50,            //scan_threshold
+    0.5            //scan_period
 };
 
 #define ST_OFF(f) M_ST_OFF(tv_param_t,f)
--- a/stream/tv.c	Thu Aug 23 14:20:31 2007 +0000
+++ b/stream/tv.c	Thu Aug 23 16:09:30 2007 +0000
@@ -30,6 +30,7 @@
 #include "libaf/af_format.h"
 #include "libmpcodecs/img_format.h"
 #include "libavutil/avstring.h"
+#include "osdep/timer.h"
 
 #include "tv.h"
 
@@ -65,6 +66,92 @@
     NULL
 };
 
+void tv_start_scan(tvi_handle_t *tvh, int start)
+{
+    mp_msg(MSGT_TV,MSGL_INFO,"start scan\n");
+    tvh->tv_param->scan=start?1:0;
+}
+
+static void tv_scan(tvi_handle_t *tvh)
+{
+    unsigned int now;
+    struct CHANLIST cl;
+    tv_channels_t *tv_channel_tmp=NULL;
+    tv_channels_t *tv_channel_add=NULL;
+    tv_scan_t* scan;
+    int found=0, index=1;
+    
+    scan = tvh->scan;
+    now=GetTimer();
+    if (!scan) {
+        scan=calloc(1,sizeof(tv_scan_t));
+        tvh->scan=scan;
+        cl = tvh->chanlist_s[scan->channel_num];
+        tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16));
+        scan->scan_timer=now+1e6*tvh->tv_param->scan_period;
+    }
+    if(scan->scan_timer>now)
+        return;
+
+    if (tv_get_signal(tvh)>tvh->tv_param->scan_threshold) {
+        cl = tvh->chanlist_s[scan->channel_num];
+        tv_channel_tmp=tv_channel_list;
+        while (tv_channel_tmp) {
+            index++;
+            if (cl.freq==tv_channel_tmp->freq){
+                found=1;
+                break;
+            }
+            tv_channel_add=tv_channel_tmp;
+            tv_channel_tmp=tv_channel_tmp->next;
+        }
+        if (!found) {
+            mp_msg(MSGT_TV, MSGL_INFO, "Found new channel: %s (#%d). \n",cl.name,index);
+            scan->new_channels++;
+            tv_channel_tmp = malloc(sizeof(tv_channels_t));
+            tv_channel_tmp->index=index;
+            tv_channel_tmp->next=NULL;
+            tv_channel_tmp->prev=tv_channel_add;
+            tv_channel_tmp->freq=cl.freq;
+            snprintf(tv_channel_tmp->name,sizeof(tv_channel_tmp->name),"ch%d",index);
+            strncpy(tv_channel_tmp->number, cl.name, 5);
+            tv_channel_tmp->number[4]='\0';
+            if (!tv_channel_list)
+                tv_channel_list=tv_channel_tmp;
+            else {
+                tv_channel_add->next=tv_channel_tmp;
+                tv_channel_list->prev=tv_channel_tmp;
+            }
+        }else
+            mp_msg(MSGT_TV, MSGL_INFO, "Found existing channel: %s-%s.\n",
+                tv_channel_tmp->number,tv_channel_tmp->name);
+    }
+    scan->channel_num++;
+    scan->scan_timer=now+1e6*tvh->tv_param->scan_period;
+    if (scan->channel_num>=chanlists[tvh->chanlist].count) {
+        tvh->tv_param->scan=0;
+        mp_msg(MSGT_TV, MSGL_INFO, "TV scan end. Found %d new channels.\n", scan->new_channels);
+        tv_channel_tmp=tv_channel_list;
+        if(tv_channel_tmp){
+            mp_msg(MSGT_TV,MSGL_INFO,"channels=");
+            while(tv_channel_tmp){
+                mp_msg(MSGT_TV,MSGL_INFO,"%s-%s",tv_channel_tmp->number,tv_channel_tmp->name);
+                if(tv_channel_tmp->next)
+                    mp_msg(MSGT_TV,MSGL_INFO,",");
+                tv_channel_tmp=tv_channel_tmp->next;
+            }
+        }
+        if (!tv_channel_current) tv_channel_current=tv_channel_list;
+        if (tv_channel_current)
+            tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16));
+        free(tvh->scan);
+        tvh->scan=NULL;
+    }else{
+        cl = tvh->chanlist_s[scan->channel_num];
+        tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16));
+        mp_msg(MSGT_TV, MSGL_INFO, "Trying: %s (%.2f). \n",cl.name,1e-3*cl.freq);
+    }
+}
 
 /* ================== DEMUX_TV ===================== */
 /*
@@ -106,6 +193,7 @@
    		ds_add_packet(demux->video,dp);
 	 }
 
+    if (tvh->tv_param->scan) tv_scan(tvh);
     return 1;
 }
 
@@ -738,6 +826,16 @@
     return(1);
 }
 
+int tv_get_signal(tvi_handle_t *tvh)
+{
+    int signal=0;
+    if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE ||
+        tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_SIGNAL, &signal)!=TVI_CONTROL_TRUE)
+        return 0;
+
+    return signal;
+}
+
 /*****************************************************************
  * \brief tune current frequency by step_interval value
  * \parameter step_interval increment value in 1/16 MHz
@@ -748,6 +846,7 @@
 int tv_step_freq(tvi_handle_t* tvh, float step_interval){
     unsigned long frequency;
 
+    tvh->tv_param->scan=0;
     tv_get_freq(tvh,&frequency);
     frequency+=step_interval;
     return tv_set_freq(tvh,frequency);
@@ -757,6 +856,7 @@
 {
     struct CHANLIST cl;
 
+    tvh->tv_param->scan=0;
     if (direction == TV_CHANNEL_LOWER)
     {
 	if (tvh->channel-1 >= 0)
@@ -784,6 +884,7 @@
 }
 
 int tv_step_channel(tvi_handle_t *tvh, int direction) {
+	tvh->tv_param->scan=0;
 	if (tv_channel_list) {
 		if (direction == TV_CHANNEL_HIGHER) {
 			tv_channel_last = tv_channel_current;
@@ -814,6 +915,7 @@
 	int i;
 	struct CHANLIST cl;
 
+        tvh->tv_param->scan=0;
         strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name);
 	for (i = 0; i < chanlists[tvh->chanlist].count; i++)
 	{
@@ -835,6 +937,7 @@
 int tv_set_channel(tvi_handle_t *tvh, char *channel) {
 	int i, channel_int;
 
+	tvh->tv_param->scan=0;
 	if (tv_channel_list) {
 		tv_channel_last = tv_channel_current;
 		channel_int = atoi(channel);
@@ -851,6 +954,7 @@
 
 int tv_last_channel(tvi_handle_t *tvh) {
 
+	tvh->tv_param->scan=0;
 	if (tv_channel_list) {
 		tv_channels_t *tmp;
 
--- a/stream/tv.h	Thu Aug 23 14:20:31 2007 +0000
+++ b/stream/tv.h	Thu Aug 23 16:09:30 2007 +0000
@@ -50,6 +50,10 @@
     char *tdevice;  ///< teletext device
     int tformat;    ///< teletext display format
     int tpage;      ///< start teletext page
+
+    int scan;
+    int scan_threshold;
+    float scan_period;
 } tv_param_t;
   
 extern tv_param_t stream_tv_defaults;
@@ -86,6 +90,7 @@
     const struct CHANLIST *chanlist_s;
     int			channel;
     tv_param_t          * tv_param;
+    void                * scan;
 } tvi_handle_t;
 
 typedef struct tv_channels_s {
@@ -101,6 +106,12 @@
 extern tv_channels_t *tv_channel_current, *tv_channel_last;
 extern char *tv_channel_last_real;
 
+typedef struct {
+    unsigned int     scan_timer;
+    int     channel_num;
+    int     new_channels;
+} tv_scan_t;
+
 #define TVI_CONTROL_FALSE		0
 #define TVI_CONTROL_TRUE		1
 #define TVI_CONTROL_NA			-1
@@ -147,6 +158,7 @@
 #define TVI_CONTROL_TUN_SET_TUNER	0x204	/* update priv->tuner struct for used input */
 #define TVI_CONTROL_TUN_GET_NORM	0x205
 #define TVI_CONTROL_TUN_SET_NORM	0x206
+#define TVI_CONTROL_TUN_GET_SIGNAL	0x207
 
 /* AUDIO controls */
 #define TVI_CONTROL_AUD_GET_FORMAT	0x301
@@ -215,10 +227,13 @@
 
 int tv_set_freq(tvi_handle_t *tvh, unsigned long freq);
 int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq);
+int tv_get_signal(tvi_handle_t *tvh);
 int tv_step_freq(tvi_handle_t *tvh, float step_interval);
 
 int tv_set_norm(tvi_handle_t *tvh, char* norm);
 
+void tv_start_scan(tvi_handle_t *tvh, int start);
+
 #define TV_NORM_PAL		1
 #define TV_NORM_NTSC		2
 #define TV_NORM_SECAM		3
--- a/stream/tvi_def.h	Thu Aug 23 14:20:31 2007 +0000
+++ b/stream/tvi_def.h	Thu Aug 23 16:09:30 2007 +0000
@@ -43,6 +43,7 @@
     h->chanlist_s = NULL;
     h->norm = -1;
     h->channel = -1;
+    h->scan = NULL;
     return(h);
 }
 
@@ -51,6 +52,8 @@
     if (h) {
 	if (h->priv)
 	    free(h->priv);
+	if (h->scan)
+	    free(h->scan);
 	free(h);
     }
 }
--- a/stream/tvi_v4l.c	Thu Aug 23 14:20:31 2007 +0000
+++ b/stream/tvi_v4l.c	Thu Aug 23 16:09:30 2007 +0000
@@ -1441,6 +1441,16 @@
 
             return(TVI_CONTROL_TRUE);
         }
+        case TVI_CONTROL_TUN_GET_SIGNAL:
+        {
+            if (ioctl(priv->video_fd, VIDIOCGTUNER, &priv->tuner) == -1)
+            {
+                mp_msg(MSGT_TV, MSGL_ERR, "ioctl get tuner failed: %s\n", strerror(errno));
+                return(TVI_CONTROL_FALSE);
+            }
+            *(int*)arg=100*(priv->tuner.signal>>8)/255;
+            return(TVI_CONTROL_TRUE);
+        }
 
         /* ========== AUDIO controls =========== */
         case TVI_CONTROL_AUD_GET_FORMAT:
--- a/stream/tvi_v4l2.c	Thu Aug 23 14:20:31 2007 +0000
+++ b/stream/tvi_v4l2.c	Thu Aug 23 16:09:30 2007 +0000
@@ -864,6 +864,14 @@
     case TVI_CONTROL_TUN_GET_NORM:
         *(int *)arg = priv->standard.index;
         return TVI_CONTROL_TRUE;
+    case TVI_CONTROL_TUN_GET_SIGNAL:
+        if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) {
+            mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n",
+                   info.short_name, strerror(errno));
+            return TVI_CONTROL_FALSE;
+        }
+        *(int*)arg=100*(priv->tuner.signal>>8)/255;
+        return TVI_CONTROL_TRUE;
     case TVI_CONTROL_TUN_SET_NORM:
         priv->standard.index = *(int *)arg;
         if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) {