[MPlayer-dev-eng] PVR Channel Navigation (5th rev)

Sven Gothel sgothel at jausoft.com
Fri May 4 10:29:59 CEST 2007


Index: mplayer/stream/stream_pvr.c
===================================================================
--- mplayer/stream/stream_pvr.c	(revision 23154)
+++ mplayer/stream/stream_pvr.c	(working copy)
@@ -40,8 +40,12 @@
 #include "help_mp.h"
 
 #include "stream.h"
-#include "tv.h"
+#include "pvr.h"
 
+#include "frequencies.h"
+
+#include "libavutil/common.h"
+
 #define PVR_DEFAULT_DEVICE "/dev/video0"
 #define PVR_MAX_CONTROLS 10
 
@@ -79,6 +83,23 @@
 int pvr_param_bitrate_peak = 0;
 char *pvr_param_stream_type = NULL;
 
+#define STATION_NAME_SIZE   256
+
+typedef struct station_elem_s {
+    char name[8];
+    int freq;
+    char station[STATION_NAME_SIZE];
+    int enabled;
+} station_elem_t;
+
+typedef struct stationlist_s {
+    char name[STATION_NAME_SIZE];
+    station_elem_t * list;
+    int total;   /* total   number */
+    int used;    /* used    number */
+    int enabled; /* enabled number */
+} stationlist_t;
+
 struct pvr_t {
   int dev_fd;
   char *video_dev;
@@ -93,7 +114,11 @@
   int saturation;
   int width;
   int height;
-  char *freq;
+  int freq;
+  int chan_idx;
+  int chan_idx_last;
+  stationlist_t stationlist;
+  char * param_channel; /* dups the tv_param_channel, or the url's channel param */
 
   /* encoder params */
   int aspect;
@@ -112,7 +137,7 @@
 {
   struct pvr_t *pvr = NULL;
 
-  pvr = malloc (sizeof (struct pvr_t)); 
+  pvr = calloc (1, sizeof (struct pvr_t)); /* set all member bytes to zero */
   pvr->dev_fd = -1;
   pvr->video_dev = strdup (PVR_DEFAULT_DEVICE);
 
@@ -126,7 +151,9 @@
   pvr->saturation = 0;
   pvr->width = -1;
   pvr->height = -1;
-  pvr->freq = NULL;
+  pvr->freq = -1;
+  pvr->chan_idx  = -1;
+  pvr->chan_idx_last  = -1;
 
   /* set default encoding settings
    * may be overlapped by user parameters
@@ -158,8 +185,13 @@
   
   if (pvr->video_dev)
     free (pvr->video_dev);
-  if (pvr->freq)
-    free (pvr->freq);
+
+  if (pvr->stationlist.list)
+    free(pvr->stationlist.list);
+
+  if(pvr->param_channel)
+    free(pvr->param_channel);
+
   free (pvr);
 }
 
@@ -489,6 +521,568 @@
   return 0;
 }
 
+/* Channel/Frequency layer */
+
+/**
+ * @brief Copy Constructor for stationlist
+ *
+ * @see parse_setup_stationlist
+ */
+static int
+copycreate_stationlist(stationlist_t * stationlist, int num)
+{
+  int i;
+
+  if (chantab<0 || !stationlist)
+    return -1;
+
+  num = FFMAX(num, chanlists[chantab].count);
+
+  if (stationlist->list)
+  {
+    free ( stationlist->list );
+    stationlist->list = NULL;
+  }
+  stationlist->total=0;
+  stationlist->enabled=0;
+  stationlist->used=0;
+  stationlist->list=calloc( num, sizeof(struct station_elem_t) );
+
+  if (!stationlist->list)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s No memory allocated for station list, giving up\n", LOG_LEVEL_V4L2);
+    return -1;
+  }
+
+  /* transport the channel list data 
+   * to our extented struct
+   */
+  stationlist->total=num;
+  strlcpy(stationlist->name, chanlists[chantab].name, STATION_NAME_SIZE);
+
+  for ( i=0; i<chanlists[chantab].count; i++ )
+  {
+    stationlist->list[i].station[0]= '\0' ; /* no station name yet */
+    strlcpy(stationlist->list[i].name, chanlists[chantab].list[i].name, STATION_NAME_SIZE);
+    stationlist->list[i].freq=chanlists[chantab].list[i].freq;
+    stationlist->list[i].enabled= 1 ; /* default enabled */
+    stationlist->enabled++;
+    stationlist->used++;
+  }
+
+  return 0;
+}
+
+static int
+print_all_stations(struct pvr_t *pvr)
+{
+  int i;
+
+  if (!pvr || !pvr->stationlist.list) 
+    return -1;
+
+  for (i=0; i<pvr->stationlist.total ; i++)
+  {
+      mp_msg (MSGT_OPEN, MSGL_INFO,
+              "%s %3d: [%c] channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+              i, (pvr->stationlist.list[i].enabled)?'X':' ',
+              pvr->stationlist.list[i].name, pvr->stationlist.list[i].freq,
+              pvr->stationlist.list[i].station);
+  } 
+  return 0;
+}
+
+/**
+ * Disables all stations
+ *
+ * @see parse_setup_stationlist
+ */
+static void
+disable_all_stations(struct pvr_t *pvr)
+{
+  int i;
+
+  for (i=0; i<pvr->stationlist.total ; i++)
+    pvr->stationlist.list[i].enabled=0;
+  pvr->stationlist.enabled=0;
+}
+
+/**
+ * Update or add a station
+ *
+ * @see parse_setup_stationlist
+ */
+static int
+set_station(struct pvr_t *pvr, const char *station, const char *channel, int freq)
+{
+  int i;
+
+  if (!pvr || !pvr->stationlist.list) 
+    return -1;
+
+  if (0>=pvr->stationlist.total || ( !channel && !freq ))
+    return -1;
+
+  /* select channel */
+  for (i=0; i<pvr->stationlist.used ; i++)
+  {
+    if (channel && !strcasecmp(pvr->stationlist.list[i].name, channel))
+        break; /* found existing channel entry */
+
+    if (freq>0 && pvr->stationlist.list[i].freq==freq)
+        break; /* found existing frequency entry */
+  }
+
+  if (i < pvr->stationlist.used)
+  {
+    /**
+     * found an existing entry,
+     * which is about to change with the user data.
+     * it is also enabled ..
+     */
+    if (! pvr->stationlist.list[i].enabled)
+    {
+        pvr->stationlist.list[i].enabled=1;
+        pvr->stationlist.enabled++;
+    }
+    if (station)
+        strlcpy(pvr->stationlist.list[i].station, station, STATION_NAME_SIZE);
+    else if (channel)
+        strlcpy(pvr->stationlist.list[i].station, channel, STATION_NAME_SIZE);
+    else
+        snprintf(pvr->stationlist.list[i].station, STATION_NAME_SIZE, "F %d", freq);
+
+    mp_msg (MSGT_OPEN, MSGL_DBG2,
+            "%s Set user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+            pvr->stationlist.list[i].name, pvr->stationlist.list[i].freq,
+            pvr->stationlist.list[i].station);
+    return 0;
+  }
+
+  /* from here on, we have to create a new entry,
+   * frequency is mandatory
+   **/
+  if (0>=freq)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+          "%s Cannot add new station/channel without frequency\n", LOG_LEVEL_V4L2);
+    return -1;
+  }
+
+  if (i >= pvr->stationlist.total)
+  {
+      /**
+       * we have to extend the stationlist about 
+       * an arbitrary size, even though this path is not performance critical
+       */
+      pvr->stationlist.total += 10;
+      pvr->stationlist.list=realloc( pvr->stationlist.list, pvr->stationlist.total * sizeof(struct station_elem_t) );
+
+      if (!pvr->stationlist.list)
+      {
+        mp_msg (MSGT_OPEN, MSGL_ERR,
+                "%s No memory allocated for station list, giving up\n", LOG_LEVEL_V4L2);
+        return -1;
+      }
+      /* clear the new space ..*/
+      memset( &(pvr->stationlist.list[pvr->stationlist.used]), 0, (pvr->stationlist.total-pvr->stationlist.used)*sizeof(struct station_elem_t));
+  }
+
+  /**
+   * here we go, our actual new entry
+   */
+  pvr->stationlist.used++;
+  pvr->stationlist.list[i].enabled=1;
+  pvr->stationlist.enabled++;
+
+  if (station)
+      strlcpy(pvr->stationlist.list[i].station, station, STATION_NAME_SIZE);
+
+  if (channel)
+      strlcpy(pvr->stationlist.list[i].name, channel, STATION_NAME_SIZE);
+  else
+      snprintf(pvr->stationlist.list[i].name, STATION_NAME_SIZE, "F %d", freq);
+
+  pvr->stationlist.list[i].freq=freq;
+
+  mp_msg (MSGT_OPEN, MSGL_DBG2,
+        "%s Add user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+        pvr->stationlist.list[i].name, pvr->stationlist.list[i].freq,
+        pvr->stationlist.list[i].station);
+
+  return 0;
+}
+
+/**
+ * Here we set our stationlist, as follow
+ *  - choose the frequency channel table, e.g. ntsc-cable
+ *  - create our stationlist, same element size as the channellist
+ *  - copy the channellist content to our stationlist
+ *  - IF the user provides his channel-mapping, THEN:
+ *    - disable all stations
+ *    - update and/or create entries in the stationlist and enable them
+ */
+static int
+parse_setup_stationlist(struct pvr_t *pvr)
+{
+  int i;
+
+  if (!pvr) 
+    return -1;
+
+  /**
+   * Create our station/channel list
+   */
+  if (tv_param_chanlist)
+  {
+    /* select channel list */
+    for (i=0; chanlists[i].name != NULL; i++)
+    {
+      if (!strcasecmp(chanlists[i].name, tv_param_chanlist))
+      {
+          chantab=i;
+          break;
+      }
+    }
+    if (!chanlists[i].name)
+    {
+        mp_msg (MSGT_OPEN, MSGL_ERR,
+                "%s unable to find channel list %s, using default %s\n", LOG_LEVEL_V4L2, 
+                tv_param_chanlist, chanlists[chantab].name);
+    } else {
+        mp_msg (MSGT_OPEN, MSGL_INFO,
+                "%s select channel list %s, entries %d\n", LOG_LEVEL_V4L2, 
+                chanlists[chantab].name, chanlists[chantab].count);
+    }
+  }
+
+  if(0>chantab)
+  {
+    mp_msg (MSGT_OPEN, MSGL_FATAL,
+            "%s No channel list selected, giving up\n", LOG_LEVEL_V4L2);
+    return -1;
+  }
+
+  if (copycreate_stationlist(&(pvr->stationlist), -1) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_FATAL,
+            "%s No memory allocated for station list, giving up\n", LOG_LEVEL_V4L2);
+    return -1;
+  }
+
+  /* Handle user channel mappings */
+  if (tv_param_channels) 
+  {
+    char channel[STATION_NAME_SIZE];
+    char station[STATION_NAME_SIZE];
+    char** channels=tv_param_channels;
+
+    disable_all_stations(pvr);
+
+    while (*channels) 
+    {
+        char* tmp=*(channels++);
+        char* sep=strchr(tmp,'-');
+        int  freq=-1;
+
+        if (!sep) continue; // Wrong syntax, but mplayer should not crash
+
+        strlcpy(station, sep + 1, STATION_NAME_SIZE);
+
+        sep[0]='\0';
+        strlcpy(channel, tmp, STATION_NAME_SIZE);
+
+        while ((sep=strchr(station, '_')))
+            sep[0]=' ';
+
+        /* if channel number is a number and larger than 1000 treat it as frequency
+         * tmp still contain pointer to null-terminated string with channel number here
+         */
+        if ((freq=atoi(channel))<=1000)
+            freq=-1; 
+
+        if (set_station(pvr, station, (freq<=0)?channel:NULL, freq) < 0)
+        {
+            mp_msg (MSGT_OPEN, MSGL_ERR,
+                    "%s Unable to set user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+                    channel, freq, station);
+        }
+    }
+  }
+  return print_all_stations(pvr);
+}
+
+static int
+get_v4l2_freq (struct pvr_t *pvr)
+{
+  int freq;
+  struct v4l2_frequency vf;
+  struct v4l2_tuner vt;
+
+  if (!pvr)
+    return -1;
+  
+  if (pvr->dev_fd < 0)
+    return -1;
+
+  memset(&vt, 0, sizeof(vt));
+  memset(&vf, 0, sizeof(vf));
+
+  if (ioctl(pvr->dev_fd, VIDIOC_G_TUNER, &vt) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set tuner (%s).\n",
+            LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  if (ioctl(pvr->dev_fd, VIDIOC_G_FREQUENCY, &vf) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get frequency %d.\n",
+            LOG_LEVEL_V4L2, errno);
+    return -1;
+  }
+  freq=vf.frequency;
+  if (!(vt.capability & V4L2_TUNER_CAP_LOW))
+      freq *= 1000;
+  freq /= 16;
+
+  return freq;
+}
+
+static int
+set_v4l2_freq (struct pvr_t *pvr)
+{
+  struct v4l2_frequency vf;
+  struct v4l2_tuner vt;
+
+  if (!pvr)
+    return -1;
+  
+  if (0>=pvr->freq)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR,
+            "%s Frequency invalid %d !!!\n", LOG_LEVEL_V4L2, pvr->freq);
+    return -1;
+  }
+
+  /* don't set the frequency, if it's already set.
+   * setting it here would interrupt the stream.
+   */
+  if (get_v4l2_freq (pvr)==pvr->freq)
+  {
+      mp_msg (MSGT_OPEN, MSGL_STATUS,
+              "%s Frequency %d already set.\n", LOG_LEVEL_V4L2, pvr->freq);
+      return 0;
+  }
+
+  if (pvr->dev_fd < 0)
+    return -1;
+
+  memset(&vf, 0, sizeof(vf));
+  memset(&vt, 0, sizeof(vt));
+
+  if (ioctl(pvr->dev_fd, VIDIOC_G_TUNER, &vt) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't get tuner (%s).\n",
+            LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  vf.type=vt.type;
+  vf.frequency=pvr->freq * 16;
+  if (!(vt.capability & V4L2_TUNER_CAP_LOW))
+      vf.frequency /= 1000;
+
+  if (ioctl(pvr->dev_fd, VIDIOC_S_FREQUENCY, &vf) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set frequency (%s).\n",
+            LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  memset(&vt, 0, sizeof(vt));
+  if (ioctl(pvr->dev_fd, VIDIOC_G_TUNER, &vt) < 0)
+  {
+    mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set tuner (%s).\n",
+            LOG_LEVEL_V4L2, strerror (errno));
+    return -1;
+  }
+
+  /* just a notification */
+  if (!vt.signal)
+  {
+      mp_msg (MSGT_OPEN, MSGL_ERR,
+              "%s NO SIGNAL at frequency %d (%d)\n", LOG_LEVEL_V4L2, pvr->freq, vf.frequency);
+  } else {
+      mp_msg (MSGT_OPEN, MSGL_STATUS,
+              "%s Got signal at frequency %d (%d)\n", LOG_LEVEL_V4L2, pvr->freq, vf.frequency);
+  }
+
+  return 0;
+}
+
+static int
+set_station_by_step(struct pvr_t *pvr, int step, int v4lAction) 
+{
+  if (!pvr || !pvr->stationlist.list) 
+    return -1;
+
+  if (pvr->stationlist.enabled>=abs(step))
+  {
+      int gotcha=0;
+      int chidx=pvr->chan_idx + step;
+
+      while(!gotcha)
+      {
+          chidx=(chidx+pvr->stationlist.used)%pvr->stationlist.used;
+
+          mp_msg (MSGT_OPEN, MSGL_DBG2,
+                "%s Offset switch: current %d, enabled %d, step %d -> %d\n", LOG_LEVEL_V4L2, 
+                pvr->chan_idx, pvr->stationlist.enabled, step, chidx);
+
+          if (!pvr->stationlist.list[chidx].enabled)
+          {
+              mp_msg (MSGT_OPEN, MSGL_DBG2,
+                    "%s Switch disabled to user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+                    pvr->stationlist.list[chidx].name, pvr->stationlist.list[chidx].freq,
+                    pvr->stationlist.list[chidx].station);
+            chidx += FFSIGN(step);
+          } else {
+            gotcha=1;
+          }
+      }
+
+      pvr->freq=pvr->stationlist.list[chidx].freq;
+      pvr->chan_idx_last=pvr->chan_idx;
+      pvr->chan_idx=chidx;
+
+      mp_msg (MSGT_OPEN, MSGL_INFO,
+            "%s Switch to user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+            pvr->stationlist.list[chidx].name, pvr->stationlist.list[chidx].freq,
+            pvr->stationlist.list[chidx].station);
+
+      if(v4lAction)
+        return set_v4l2_freq (pvr);
+
+      return (pvr->freq>0)?0:-1;
+  }
+
+  mp_msg (MSGT_OPEN, MSGL_ERR,
+          "%s Ooops couldn't set freq by channel entry step %d to current %d, enabled %d\n", LOG_LEVEL_V4L2, 
+          step, pvr->chan_idx, pvr->stationlist.enabled);
+  return -1;
+}
+
+static int
+set_station_by_channelname_or_freq(struct pvr_t *pvr, const char *channel, int freq, int v4lAction)
+{
+  int i=0;
+
+  if (!pvr || !pvr->stationlist.list) 
+    return -1;
+
+  if (0>=pvr->stationlist.enabled)
+  {
+    mp_msg (MSGT_OPEN, MSGL_WARN,
+            "%s No enabled station, cannot switch channel/frequency\n", LOG_LEVEL_V4L2);
+    return -1;
+  }
+
+  if (channel)
+  {
+      /* select by channel */
+      for (i=0; i<pvr->stationlist.used ; i++)
+      {
+        if (!strcasecmp(pvr->stationlist.list[i].name, channel))
+        {
+            if (!pvr->stationlist.list[i].enabled)
+            {
+                mp_msg (MSGT_OPEN, MSGL_WARN,
+                    "%s Switch disabled to user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+                    pvr->stationlist.list[i].name, pvr->stationlist.list[i].freq,
+                    pvr->stationlist.list[i].station);
+
+                return -1;
+            }
+            pvr->freq=pvr->stationlist.list[i].freq;
+            pvr->chan_idx_last=pvr->chan_idx;
+            pvr->chan_idx=i;
+            break;
+        }
+      }
+  }
+  else if (freq>=0)
+  {
+      /* select by freq */
+      for (i=0; i<pvr->stationlist.used ; i++)
+      {
+        if (pvr->stationlist.list[i].freq==freq)
+        {
+            if (!pvr->stationlist.list[i].enabled)
+            {
+                mp_msg (MSGT_OPEN, MSGL_WARN,
+                    "%s Switch disabled to user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+                    pvr->stationlist.list[i].name, pvr->stationlist.list[i].freq,
+                    pvr->stationlist.list[i].station);
+
+                return -1;
+            }
+            pvr->freq=pvr->stationlist.list[i].freq;
+            pvr->chan_idx_last=pvr->chan_idx;
+            pvr->chan_idx=i;
+            break;
+        }
+      }
+  }
+
+  if (i >= pvr->stationlist.used)
+  {
+    if(channel)
+    {
+        mp_msg (MSGT_OPEN, MSGL_WARN,
+                "%s unable to find channel %s\n", LOG_LEVEL_V4L2, channel);
+    } else {
+        mp_msg (MSGT_OPEN, MSGL_WARN,
+                "%s unable to find frequency %d\n", LOG_LEVEL_V4L2, freq);
+    }
+    return -1;
+  }
+  mp_msg (MSGT_OPEN, MSGL_INFO,
+      "%s Switch to user station channel: %8s - freq: %8d - station: %s\n", LOG_LEVEL_V4L2, 
+      pvr->stationlist.list[i].name, pvr->stationlist.list[i].freq,
+      pvr->stationlist.list[i].station);
+
+  if(v4lAction)
+      return set_v4l2_freq (pvr);
+
+  return (pvr->freq>0)?0:-1;
+}
+
+static int 
+force_freq_step (struct pvr_t *pvr, int step)
+{
+  int freq;
+
+  if (!pvr) 
+    return -1;
+
+  freq=pvr->freq+step;
+
+  if (freq)
+  {
+     mp_msg (MSGT_OPEN, MSGL_INFO,
+            "%s Force Frequency %d + %d = %d \n", LOG_LEVEL_V4L2, 
+            pvr->freq, step, freq);
+
+     pvr->freq=freq;
+
+     return set_v4l2_freq (pvr);
+  } 
+  return -1;
+  
+}
+
 /* V4L2 layer */
 
 static void
@@ -497,6 +1091,35 @@
   if (!pvr)
     return;
   
+  /**
+   * Create our station/channel list
+   */
+  parse_setup_stationlist(pvr);
+
+  if (pvr->param_channel)
+  {
+      if (set_station_by_channelname_or_freq(pvr, pvr->param_channel, -1, 0) >= 0)
+      {
+          if (tv_param_freq)
+          {
+            mp_msg (MSGT_OPEN, MSGL_HINT,
+                    "%s tv param freq %s is overwritten by channel setting freq %d\n", LOG_LEVEL_V4L2, 
+                    tv_param_freq, pvr->freq);
+          }
+      }
+  } 
+  
+  if (pvr->freq<0 && tv_param_freq )
+  {
+      mp_msg (MSGT_OPEN, MSGL_HINT,
+              "%s tv param freq %s is used directly\n", LOG_LEVEL_V4L2, tv_param_freq);
+      if(set_station_by_channelname_or_freq(pvr, NULL, atoi(tv_param_freq),0)<0)
+      {
+            mp_msg (MSGT_OPEN, MSGL_WARN,
+                    "%s tv param freq %s invalid to set station\n", LOG_LEVEL_V4L2, tv_param_freq);
+      }
+  }
+
   if (tv_param_device)
   {
     if (pvr->video_dev)
@@ -531,8 +1154,6 @@
   if (tv_param_height)
     pvr->height = tv_param_height;
 
-  if (tv_param_freq)
-    pvr->freq = strdup (tv_param_freq);
 }
 
 static int
@@ -694,24 +1315,21 @@
     }
   }
 
-  /* -tv freq=x */
-  if (pvr->freq)
+  if (0>=pvr->freq)
   {
-    struct v4l2_frequency vf;
-    vf.tuner = 0;
-    vf.type = 0;
-    vf.frequency = strtol (pvr->freq, 0L, 0);
-    mp_msg (MSGT_OPEN, MSGL_INFO,
-            "%s setting frequency to %d\n", LOG_LEVEL_V4L2, vf.frequency);
-    
-    if (ioctl (pvr->dev_fd, VIDIOC_S_FREQUENCY, &vf) < 0)
-    {
-      mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set frequency (%s).\n",
-              LOG_LEVEL_V4L2, strerror (errno));
-      return -1;
-    }
+      int freq = get_v4l2_freq (pvr);
+      mp_msg (MSGT_OPEN, MSGL_INFO,
+              "%s Using current set frequency %d, to set channel\n", LOG_LEVEL_V4L2, freq);
+      if (0<freq)
+      {
+            return set_station_by_channelname_or_freq(pvr, NULL, freq, 1);
+      }
   }
 
+  if (0<pvr->freq)
+  {
+      return set_v4l2_freq (pvr) ;
+  }
   return 0;
 }
 
@@ -935,6 +1553,15 @@
   
   pvr = pvr_init ();
 
+  /**
+   * if the url, i.e. 'pvr://8', contains the channel, use it,
+   * else use the tv parameter.
+   */
+  if (stream->url && strlen (stream->url) > 6 && stream->url[6] != '\0')
+    pvr->param_channel = strdup (stream->url + 6);
+  else if (tv_param_channel && strlen(tv_param_channel))
+    pvr->param_channel = strdup (tv_param_channel);
+  
   parse_v4l2_tv_options (pvr);
   parse_encoder_options (pvr);
   
@@ -1029,6 +1656,130 @@
   return STREAM_OK;
 }
 
+/* Public access */
+
+/**
+ * @brief Get the current station name.
+ *        The pointer is valid, till the stream is closed.
+ * @return The stream's station name
+ */
+const char *
+pvr_get_current_stationname (stream_t *stream)
+{
+  struct pvr_t *pvr;
+
+  if (!stream || stream->type != STREAMTYPE_PVR)
+    return NULL;
+  
+  pvr = (struct pvr_t *) stream->priv;
+
+  if (pvr->stationlist.list && pvr->stationlist.used>pvr->chan_idx && pvr->chan_idx>=0)
+  {
+        return pvr->stationlist.list[pvr->chan_idx].station;
+  }
+  return NULL;
+}
+
+/**
+ * @brief Get the current channel name.
+ *        The pointer is valid, till the stream is closed.
+ * @return The stream's channel name 
+ */
+const char *
+pvr_get_current_channelname (stream_t *stream)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  if (pvr->stationlist.list && pvr->stationlist.used>pvr->chan_idx && pvr->chan_idx>=0)
+  {
+        return pvr->stationlist.list[pvr->chan_idx].name;
+  }
+  return NULL;
+}
+
+/**
+ * @brief Get the current frequency.
+ * @return frequency
+ */
+int pvr_get_current_frequency (stream_t *stream)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  return pvr->freq;
+}
+
+/**
+ * @brief Set the current station using the channel name.
+ *        This function will fail,
+ *        if the channel does not exist, or the station is not enabled
+ * @return 0 if the station is available, otherwise -1
+ */
+int
+pvr_set_channel (stream_t *stream, const char * channel)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  return set_station_by_channelname_or_freq(pvr, channel, -1, 1);
+}
+
+/**
+ * @brief Set the current station using to the last set channel
+ * @return 0 if the station is available, otherwise -1
+ */
+int
+pvr_set_lastchannel (stream_t *stream)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  if (pvr->stationlist.list && pvr->stationlist.used>pvr->chan_idx_last && pvr->chan_idx_last>=0)
+  {
+      return set_station_by_channelname_or_freq(pvr, pvr->stationlist.list[pvr->chan_idx_last].name, -1, 1);
+  }
+  return -1;
+}
+
+/**
+ * @brief Set the current channel using the frequency.
+ *        This function will fail,
+ *        if the frequency does not exist, or the station is not enabled
+ * @return 0 if the station is available, otherwise -1
+ */
+int
+pvr_set_freq (stream_t *stream, int freq)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  return set_station_by_channelname_or_freq(pvr, NULL, freq, 1);
+}
+
+/**
+ * @brief Set the current station while stepping.
+ *        This function will fail,
+ *        if the station does not exist, or the station is not enabled
+ * @return 0 if the station is available, otherwise -1
+ */
+int
+pvr_set_channel_step(stream_t *stream, int step)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  return set_station_by_step(pvr, step, 1);
+}
+
+/**
+ * @brief Set the current frequency while stepping
+ *        This function will fail,
+ *        if the frequency is invalid, i.e. <0
+ * @return 0 if success, otherwise -1
+ */
+int
+pvr_force_freq_step(stream_t *stream, int step)
+{
+  struct pvr_t *pvr = (struct pvr_t *) stream->priv;
+
+  return force_freq_step(pvr, step);
+}
+
 stream_info_t stream_info_pvr = {
   "V4L2 MPEG Input (a.k.a PVR)",
   "pvr",
Index: mplayer/stream/pvr.h
===================================================================
--- mplayer/stream/pvr.h	(revision 0)
+++ mplayer/stream/pvr.h	(revision 0)
@@ -0,0 +1,20 @@
+#ifndef PVR_H
+#define PVR_H
+
+#include "tv.h"
+
+int          pvr_get_current_frequency (stream_t *stream);
+const char * pvr_get_current_stationname (stream_t *stream);
+const char * pvr_get_current_channelname (stream_t *stream);
+
+int pvr_set_channel (stream_t *stream, const char * channel);
+
+int pvr_set_lastchannel (stream_t *stream);
+
+int pvr_set_freq (stream_t *stream, int freq);
+
+int pvr_set_channel_step(stream_t *stream, int step);
+
+int pvr_force_freq_step(stream_t *stream, int step);
+
+#endif /* PVR_H */
Index: mplayer/command.c
===================================================================
--- mplayer/command.c	(revision 23154)
+++ mplayer/command.c	(working copy)
@@ -32,6 +32,9 @@
 #ifdef USE_RADIO
 #include "stream/stream_radio.h"
 #endif
+#ifdef HAVE_PVR
+#include "stream/pvr.h"
+#endif
 #ifdef HAS_DVBIN_SUPPORT
 #include "stream/dvbin.h"
 #endif
@@ -1937,14 +1940,32 @@
 #ifdef USE_TV
 	case MP_CMD_TV_SET_FREQ:
 	    if (mpctx->file_format == DEMUXER_TYPE_TV)
-		tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
-			    cmd->args[0].v.f * 16.0);
+            tv_set_freq((tvi_handle_t *) (mpctx->demuxer->priv),
+                    cmd->args[0].v.f * 16.0);
+#ifdef HAVE_PVR
+        else if ( mpctx->stream!=NULL && STREAMTYPE_PVR == mpctx->stream->type )
+        {
+            pvr_set_freq (mpctx->stream, ROUND(cmd->args[0].v.f));
+            set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+                pvr_get_current_channelname(mpctx->stream),
+                pvr_get_current_stationname(mpctx->stream));
+        }
+#endif /* HAVE_PVR */
 	    break;
 
 	case MP_CMD_TV_STEP_FREQ:
 	    if (mpctx->file_format == DEMUXER_TYPE_TV)
-		tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv),
-			    cmd->args[0].v.f * 16.0);
+            tv_step_freq((tvi_handle_t *) (mpctx->demuxer->priv),
+                    cmd->args[0].v.f * 16.0);
+#ifdef HAVE_PVR
+        else if ( mpctx->stream!=NULL && STREAMTYPE_PVR == mpctx->stream->type )
+        {
+            pvr_force_freq_step(mpctx->stream, ROUND(cmd->args[0].v.f));
+            set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: f %d",
+                pvr_get_current_channelname(mpctx->stream),
+                pvr_get_current_frequency(mpctx->stream));
+        }
+#endif /* HAVE_PVR */
 	    break;
 
 	case MP_CMD_TV_SET_NORM:
@@ -1971,6 +1992,15 @@
 			//vo_osd_changed(OSDTYPE_SUBTITLE);
 		    }
 		}
+#ifdef HAVE_PVR
+        else if ( mpctx->stream!=NULL && STREAMTYPE_PVR == mpctx->stream->type )
+        {
+            pvr_set_channel_step(mpctx->stream, cmd->args[0].v.i);
+            set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+                pvr_get_current_channelname(mpctx->stream),
+                pvr_get_current_stationname(mpctx->stream));
+        }
+#endif /* HAVE_PVR */
 	    }
 #ifdef HAS_DVBIN_SUPPORT
 	    if ((mpctx->stream->type == STREAMTYPE_DVB)
@@ -2004,6 +2034,15 @@
 		    //vo_osd_changed(OSDTYPE_SUBTITLE);
 		}
 	    }
+#ifdef HAVE_PVR
+        else if ( mpctx->stream!=NULL && STREAMTYPE_PVR == mpctx->stream->type )
+        {
+            pvr_set_channel(mpctx->stream, cmd->args[0].v.s);
+            set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+                pvr_get_current_channelname(mpctx->stream),
+                pvr_get_current_stationname(mpctx->stream));
+        }
+#endif /* HAVE_PVR */
 	    break;
 
 #ifdef HAS_DVBIN_SUPPORT
@@ -2034,6 +2073,15 @@
 		    //vo_osd_changed(OSDTYPE_SUBTITLE);
 		}
 	    }
+#ifdef HAVE_PVR
+        else if ( mpctx->stream!=NULL && STREAMTYPE_PVR == mpctx->stream->type )
+        {
+            pvr_set_lastchannel(mpctx->stream);
+            set_osd_msg(OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+                pvr_get_current_channelname(mpctx->stream),
+                pvr_get_current_stationname(mpctx->stream));
+        }
+#endif /* HAVE_PVR */
 	    break;
 
 	case MP_CMD_TV_STEP_NORM:

-- 
health & wealth
mailto:sgothel at jausoft.com ; www  : http://www.jausoft.ca ; pgp: http://www.jausoft.com/gpg/
land : +1 (780) 637 3842 ; cell: +1 (780) 952 4481
Timezone MST: EST-2, UTC-7, CET-8 ; MDT: EDT-2, UTC-6, CEDT-8
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MPlayer-PVR_ChannelFeature-v05.diff
Type: text/x-diff
Size: 27691 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20070504/ad71fb13/attachment.diff>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20070504/ad71fb13/attachment.pgp>


More information about the MPlayer-dev-eng mailing list