[MPlayer-dev-eng] PVR Channel Navigation (3rd rev)
Sven Gothel
sgothel at jausoft.com
Sun Apr 29 13:23:27 CEST 2007
Thanks to Reimar
for his review efforts.
Index: mplayer/stream/stream_pvr.c
===================================================================
--- mplayer/stream/stream_pvr.c (revision 23154)
+++ mplayer/stream/stream_pvr.c (working copy)
@@ -22,6 +22,7 @@
#include "config.h"
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -40,8 +41,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 +84,23 @@
int pvr_param_bitrate_peak = 0;
char *pvr_param_stream_type = NULL;
+#define STATIONNAMESZ 256
+
+struct STATIONELEM {
+ char name[8];
+ int freq;
+ char station[STATIONNAMESZ];
+ int enabled;
+};
+
+struct STATIONLIST {
+ char name[STATIONNAMESZ];
+ struct STATIONELEM *list;
+ int total; /* total number */
+ int used; /* used number */
+ int enabled; /* enabled number */
+};
+
struct pvr_t {
int dev_fd;
char *video_dev;
@@ -93,7 +115,10 @@
int saturation;
int width;
int height;
- char *freq;
+ int freq;
+ int chanidx;
+ int chanidx_last;
+ struct STATIONLIST stationlist;
/* encoder params */
int aspect;
@@ -126,7 +151,14 @@
pvr->saturation = 0;
pvr->width = -1;
pvr->height = -1;
- pvr->freq = NULL;
+ pvr->freq = -1;
+ pvr->chanidx = -1;
+ pvr->chanidx_last = -1;
+ pvr->stationlist.name[0] = '\0';
+ pvr->stationlist.list = NULL;
+ pvr->stationlist.total = 0;
+ pvr->stationlist.used = 0;
+ pvr->stationlist.enabled = 0;
/* set default encoding settings
* may be overlapped by user parameters
@@ -158,8 +190,10 @@
if (pvr->video_dev)
free (pvr->video_dev);
- if (pvr->freq)
- free (pvr->freq);
+
+ if ( NULL!= pvr->stationlist.list )
+ free(pvr->stationlist.list);
+
free (pvr);
}
@@ -489,14 +523,643 @@
return 0;
}
+/* Channel/Frequency layer */
+
+/**
+ * Copy Constructor for stationlist
+ *
+ * @see parse_setup_stationlist
+ */
+static int
+copycreate_stationlist(struct pvr_t *pvr, int num)
+{
+ int i;
+
+ if ( chantab<0 || !pvr )
+ return -1;
+
+ num = FFMAX(num, chanlists[chantab].count);
+
+ if ( pvr->stationlist.list != NULL )
+ {
+ free ( pvr->stationlist.list );
+ pvr->stationlist.list = NULL;
+ }
+ pvr->stationlist.total= 0;
+ pvr->stationlist.enabled=0;
+ pvr->stationlist.used=0;
+ pvr->stationlist.list = calloc( num, sizeof(struct STATIONELEM) );
+
+ if ( pvr->stationlist.list == NULL )
+ {
+ 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
+ */
+ pvr->stationlist.total = num;
+ strlcpy(pvr->stationlist.name, chanlists[chantab].name, STATIONNAMESZ);
+
+ for ( i=0; i<chanlists[chantab].count; i++ )
+ {
+ pvr->stationlist.list[i].station[0]= '\0' ; /* no station name yet */
+ strlcpy(pvr->stationlist.list[i].name, chanlists[chantab].list[i].name, STATIONNAMESZ);
+ pvr->stationlist.list[i].freq = chanlists[chantab].list[i].freq;
+ pvr->stationlist.list[i].enabled= 1 ; /* default enabled */
+ pvr->stationlist.enabled++;
+ pvr->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 int
+disable_all_stations(struct pvr_t *pvr)
+{
+ int i;
+
+ if (!pvr || !pvr->stationlist.list)
+ return -1;
+
+ for (i = 0; i<pvr->stationlist.total ; i++)
+ {
+ pvr->stationlist.list[i].enabled= 0;
+ }
+ pvr->stationlist.enabled=0;
+ return 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, STATIONNAMESZ);
+ } else if ( channel ) {
+ strlcpy(pvr->stationlist.list[i].station, channel, STATIONNAMESZ);
+ } else {
+ snprintf(pvr->stationlist.list[i].station, STATIONNAMESZ, "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)
+ {
+ assert(i == pvr->stationlist.used);
+ assert(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 STATIONELEM) );
+
+ 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 STATIONELEM));
+ }
+
+ /**
+ * 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, STATIONNAMESZ);
+ }
+ if ( channel ) {
+ strlcpy(pvr->stationlist.list[i].name, channel, STATIONNAMESZ);
+ } else {
+ snprintf(pvr->stationlist.list[i].name, STATIONNAMESZ, "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 == NULL )
+ {
+ 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, -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[STATIONNAMESZ];
+ char station[STATIONNAMESZ];
+ char** channels = tv_param_channels;
+
+ (void) disable_all_stations(pvr);
+
+ while (*channels)
+ {
+ char* tmp = *(channels++);
+ char* sep = strchr(tmp,'-');
+ int freq = -1;
+ int i;
+
+ if (!sep) continue; // Wrong syntax, but mplayer should not crash
+
+ strlcpy(station, sep + 1, STATIONNAMESZ);
+
+ sep[0] = '\0';
+ strlcpy(channel, tmp, STATIONNAMESZ);
+
+ while ((sep=strchr(station, '_')))
+ {
+ sep[0] = ' ';
+ }
+
+ // if channel number is a number and larger than 1000 threat it as frequency
+ // tmp still contain pointer to null-terminated string with channel number here
+ if (atoi(channel)>1000)
+ {
+ freq=atoi(channel);
+ }
+ 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);
+ }
+ }
+ }
+ (void) 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;
+ }
+
+ vf.type = 0;
+ 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 (pvr->freq>0)
+ {
+ if ( get_v4l2_freq (pvr) == pvr->freq )
+ {
+ mp_msg (MSGT_OPEN, MSGL_STATUS,
+ "%s Frequency %d allready set.\n", LOG_LEVEL_V4L2, pvr->freq);
+ return 0;
+ }
+ }
+
+ if (pvr->dev_fd < 0)
+ return -1;
+
+ if (0>=pvr->freq)
+ {
+ mp_msg (MSGT_OPEN, MSGL_ERR,
+ "%s Frequency invalid %d !!!\n", LOG_LEVEL_V4L2, pvr->freq);
+ 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.tuner = 0;
+ 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;
+ }
+
+ if (!vt.signal)
+ {
+ mp_msg (MSGT_OPEN, MSGL_ERR,
+ "%s NO SIGNAL at frequency %d (%d)\n", LOG_LEVEL_V4L2, pvr->freq, vf.frequency);
+ /* still return 0, since this is 'just informal' */
+ } 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_channeloffset(struct pvr_t *pvr, int offset, int v4lAction)
+{
+ if (!pvr || !pvr->stationlist.list)
+ return -1;
+
+ if ( pvr->stationlist.enabled>=abs(offset) )
+ {
+ int gotcha=0;
+ int chidx=pvr->chanidx + offset;
+
+ while(!gotcha)
+ {
+ if ( chidx < 0 ) chidx += pvr->stationlist.used;
+ if ( chidx >= pvr->stationlist.used ) chidx -= pvr->stationlist.used;
+
+ mp_msg (MSGT_OPEN, MSGL_DBG2,
+ "%s Offset switch: current %d, enabled %d, offset %d -> %d\n", LOG_LEVEL_V4L2,
+ pvr->chanidx, pvr->stationlist.enabled, offset, 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 += (offset>0)?1:-1;
+ } else {
+ gotcha=1;
+ }
+ }
+
+ pvr->freq = pvr->stationlist.list[chidx].freq;
+ pvr->chanidx_last = pvr->chanidx;
+ pvr->chanidx = 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 offset %d to current %d, enabled %d\n", LOG_LEVEL_V4L2,
+ offset, pvr->chanidx, pvr->stationlist.enabled);
+ return -1;
+}
+
+static int
+set_station_by_channelname(struct pvr_t *pvr, const char *channel, int v4lAction)
+{
+ if (!pvr || !pvr->stationlist.list)
+ return -1;
+
+ if ( pvr->stationlist.enabled>0 && channel )
+ {
+ int i;
+
+ /* select 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->chanidx_last = pvr->chanidx;
+ pvr->chanidx = i;
+ break;
+ }
+ }
+
+ if (i >= pvr->stationlist.used)
+ {
+ mp_msg (MSGT_OPEN, MSGL_WARN,
+ "%s unable to find channel %s\n", LOG_LEVEL_V4L2, channel);
+ } else {
+ 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;
+ }
+ }
+ return -1;
+}
+
+static int
+set_station_by_freq(struct pvr_t *pvr, int freq, int v4lAction)
+{
+ if (!pvr || !pvr->stationlist.list)
+ return -1;
+
+ if ( pvr->stationlist.enabled>0 && freq )
+ {
+ int i;
+
+ /* select channel */
+ 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->chanidx_last = pvr->chanidx;
+ pvr->chanidx = i;
+ break;
+ }
+ }
+
+ if (i >= pvr->stationlist.used)
+ {
+ mp_msg (MSGT_OPEN, MSGL_ERR,
+ "%s unable to find frequency %d from list\n", LOG_LEVEL_V4L2,
+ freq);
+ } else {
+ 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;
+ }
+ }
+ return -1;
+
+}
+
+static int
+force_freq_offset (struct pvr_t *pvr, int offset)
+{
+ int freq;
+
+ if (!pvr)
+ return -1;
+
+ freq = pvr->freq+offset;
+
+ if ( freq )
+ {
+ mp_msg (MSGT_OPEN, MSGL_INFO,
+ "%s Force Frequency %d + %d = %d \n", LOG_LEVEL_V4L2,
+ pvr->freq, offset, freq);
+
+ pvr->freq=freq;
+
+ return set_v4l2_freq (pvr);
+ }
+ return -1;
+
+}
+
/* V4L2 layer */
static void
parse_v4l2_tv_options (struct pvr_t *pvr)
{
+ int i;
+
if (!pvr)
return;
+ /**
+ * Create our station/channel list
+ */
+ parse_setup_stationlist(pvr);
+
+ if (tv_param_channel)
+ {
+ if ( set_station_by_channelname(pvr, tv_param_channel, 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);
+ (void) set_station_by_freq(pvr, atoi(tv_param_freq),0);
+ }
+
if (tv_param_device)
{
if (pvr->video_dev)
@@ -531,8 +1194,6 @@
if (tv_param_height)
pvr->height = tv_param_height;
- if (tv_param_freq)
- pvr->freq = strdup (tv_param_freq);
}
static int
@@ -694,27 +1355,23 @@
}
}
- /* -tv freq=x */
- if (pvr->freq)
+ if (pvr->freq<0 )
{
- 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);
+ if ( freq>0 )
+ {
+ (void) set_station_by_freq(pvr, freq, 0);
+ }
}
+ if (pvr->freq>0)
+ {
+ return set_v4l2_freq (pvr) ;
+ }
return 0;
}
+
static int
v4l2_list_capabilities (struct pvr_t *pvr)
{
@@ -916,13 +1573,14 @@
"%s read (%d) bytes\n", LOG_LEVEL_PVR, pos);
}
}
-
+
if (!pos)
mp_msg (MSGT_OPEN, MSGL_ERR, "%s read %d bytes\n", LOG_LEVEL_PVR, pos);
return pos;
}
+
static int
pvr_stream_open (stream_t *stream, int mode, void *opts, int *file_format)
{
@@ -933,9 +1591,13 @@
if (mode != STREAM_READ)
return STREAM_UNSUPORTED;
+ if (strlen (stream->url) > 6 && stream->url[6] != '\0')
+ tv_param_channel = strdup (stream->url + 6);
+
pvr = pvr_init ();
parse_v4l2_tv_options (pvr);
+
parse_encoder_options (pvr);
/* open device */
@@ -1029,12 +1691,129 @@
return STREAM_OK;
}
+/* Public access */
+
+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 (NULL!=pvr->stationlist.list && pvr->stationlist.used>pvr->chanidx && pvr->chanidx>=0)
+ {
+ return pvr->stationlist.list[pvr->chanidx].station;
+ }
+ return NULL;
+}
+
+const char *
+pvr_get_current_channelname (stream_t *stream)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return NULL;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ if (NULL!=pvr->stationlist.list && pvr->stationlist.used>pvr->chanidx && pvr->chanidx>=0)
+ {
+ return pvr->stationlist.list[pvr->chanidx].name;
+ }
+ return NULL;
+}
+
+int pvr_get_current_frequency (stream_t *stream)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return -1;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ return pvr->freq;
+}
+
+int
+pvr_set_channel (stream_t *stream, const char * channel)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return -1;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ return set_station_by_channelname(pvr, channel, 1);
+}
+
+int
+pvr_set_lastchannel (stream_t *stream)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return -1;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ if (NULL!=pvr->stationlist.list && pvr->stationlist.used>pvr->chanidx_last && pvr->chanidx_last>=0)
+ {
+ return set_station_by_channelname(pvr, pvr->stationlist.list[pvr->chanidx_last].name, 1);
+ }
+ return -1;
+}
+
+int
+pvr_set_freq (stream_t *stream, int freq)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return -1;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ return set_station_by_freq(pvr, freq, 1);
+}
+
+int
+pvr_set_channel_offset(stream_t *stream, int offset)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return -1;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ return set_station_by_channeloffset(pvr, offset, 1);
+}
+
+int
+pvr_force_freq_offset(stream_t *stream, int offset)
+{
+ struct pvr_t *pvr;
+
+ if (!stream || stream->type != STREAMTYPE_PVR)
+ return -1;
+
+ pvr = (struct pvr_t *) stream->priv;
+
+ return force_freq_offset(pvr, offset);
+}
+
stream_info_t stream_info_pvr = {
"V4L2 MPEG Input (a.k.a PVR)",
"pvr",
"Benjamin Zores",
"",
- pvr_stream_open,
+ pvr_stream_open,
{ "pvr", NULL },
NULL,
1
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_offset(stream_t *stream, int offset);
+
+int pvr_force_freq_offset(stream_t *stream, int offset);
+
+#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,37 @@
#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_offset(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 +1997,15 @@
//vo_osd_changed(OSDTYPE_SUBTITLE);
}
}
+#ifdef HAVE_PVR
+ else if ( mpctx->stream!=NULL && STREAMTYPE_PVR == mpctx->stream->type )
+ {
+ pvr_set_channel_offset(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 +2039,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 +2078,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:
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MPlayer-PVR_ChannelFeature-v03.diff
Type: text/x-diff
Size: 27949 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20070429/9b2fd638/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/20070429/9b2fd638/attachment.pgp>
More information about the MPlayer-dev-eng
mailing list