[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