Author: duncan
Date: Wed Oct 17 03:52:27 2007
New Revision: 9992
Log:
[ 1814720 ] PATCH Major ivtv_xine_tv update
Patch from Richard van Paasen applied
Modified:
branches/rel-1/freevo/freevo_config.py
branches/rel-1/freevo/local_conf.py.example
branches/rel-1/freevo/src/tv/channels.py
branches/rel-1/freevo/src/tv/plugins/ivtv_xine_tv.py
Modified: branches/rel-1/freevo/freevo_config.py
==============================================================================
--- branches/rel-1/freevo/freevo_config.py (original)
+++ branches/rel-1/freevo/freevo_config.py Wed Oct 17 03:52:27 2007
@@ -319,6 +319,11 @@
VOLUME_MIXER_DEV to MIXER_DEVICE
ENABLE_SHUTDOWN_SYS to SHUTDOWN_SYS_ENABLE
Added MIXER_VOLUME_STEP to allow the mixer volume change to be specified
+ Added for IVTV XINE TV:
+ XINE_TV_CONFIRM_STOP
+ XINE_TV_PROGRESSIVE_SEEK
+ XINE_TV_PROGRESSIVE_SEEK_THRESHOLD
+ XINE_TV_PROGRESSIVE_SEEK_INCREMENT
'''),
]
@@ -1570,11 +1575,31 @@
# Set to True is xine supports get_time this enables the position to be saved
XINE_BOOKMARK = False
-# Defaults to XINE_VO/AO_DEV:
+# -- TV/XINE configuration --
+
+# Video output device for TV. For Hauppage PVR x50,
+# use "xxmc" if you have hardware acceleration enabled.
+# Otherwise, see XINE_VO_DEV
XINE_TV_VO_DEV = None
+
+# Audio output device to use for TV. See XINE_AO_DEV.
XINE_TV_AO_DEV = None
+
+# This specifies the path and filemask that xine uses for
+# timeshifting. File can get quite big (several gigabytes)
XINE_TV_TIMESHIFT_FILEMASK = "you must set XINE_TV_TIMESHIFT_FILEMASK in your
local_conf.py"
+# Stop confirmation: press STOP twice to return to menu
+XINE_TV_CONFIRM_STOP = True
+
+# This enables the progressive seek feature. The speed
+# for seeking (fast forward and rewind) is increased
+# automatically. The speed is increased every [THRESHOLD]
+# seconds in steps of [INCREMENT] secnds.
+XINE_TV_PROGRESSIVE_SEEK = True
+XINE_TV_PROGRESSIVE_SEEK_THRESHOLD = 2
+XINE_TV_PROGRESSIVE_SEEK_INCREMENT = 5
+
# ======================================================================
# Freevo TV settings:
# ======================================================================
Modified: branches/rel-1/freevo/local_conf.py.example
==============================================================================
--- branches/rel-1/freevo/local_conf.py.example (original)
+++ branches/rel-1/freevo/local_conf.py.example Wed Oct 17 03:52:27 2007
@@ -1130,15 +1130,25 @@
# Video output device for TV. For Hauppage PVR x50,
# use "xxmc" if you have hardware acceleration enabled.
# Otherwise, see XINE_VO_DEV
-#XINE_TV_VO_DEV = "xxmc"
+# XINE_TV_VO_DEV = "xxmc"
# Audio output device to use for TV. See XINE_AO_DEV.
-#XINE_TV_AO_DEV = "alsa"
+# XINE_TV_AO_DEV = "alsa"
-# This specifies the path and filemask that
-# xine uses for timeshifting. File can get
-# quite big (several gigabytes)
-#XINE_TV_TIMESHIFT_FILEMASK = "/tmp/xine-buf-"
+# This specifies the path and filemask that xine uses for
+# timeshifting. File can get quite big (several gigabytes)
+# XINE_TV_TIMESHIFT_FILEMASK = "/tmp/xine-buf-"
+
+# Stop confirmation: press STOP twice to return to menu
+# XINE_TV_CONFIRM_STOP = True
+
+# This enables the progressive seek feature. The speed
+# for seeking (fast forward and rewind) is increased
+# automatically. The speed is increased every [THRESHOLD]
+# seconds in steps of [INCREMENT] secnds.
+# XINE_TV_PROGRESSIVE_SEEK = True
+# XINE_TV_PROGRESSIVE_SEEK_THRESHOLD = 2
+# XINE_TV_PROGRESSIVE_SEEK_INCREMENT = 5
# ======================================================================
# Freevo TV settings:
Modified: branches/rel-1/freevo/src/tv/channels.py
==============================================================================
--- branches/rel-1/freevo/src/tv/channels.py (original)
+++ branches/rel-1/freevo/src/tv/channels.py Wed Oct 17 03:52:27 2007
@@ -248,21 +248,23 @@
app.write(app_cmd)
- def getChannelInfo(self):
+ def getChannelInfo(self, showtime=True):
'''Get program info for the current channel'''
tuner_id = self.getChannel()
chan_name = config.TV_CHANNELS[self.chan_index][1]
chan_id = config.TV_CHANNELS[self.chan_index][0]
- channels = epg_xmltv.get_guide().GetPrograms(start=time.time(),
- stop=time.time(),
chanids=[chan_id])
+ channels = epg_xmltv.get_guide().GetPrograms(start=time.time(),
stop=time.time(), chanids=[chan_id])
if channels and channels[0] and channels[0].programs:
- start_s = time.strftime(config.TV_TIMEFORMAT,
time.localtime(channels[0].programs[0].start))
- stop_s = time.strftime(config.TV_TIMEFORMAT,
time.localtime(channels[0].programs[0].stop))
- ts = '(%s-%s)' % (start_s, stop_s)
- prog_info = '%s %s' % (ts, channels[0].programs[0].title)
+ if showtime:
+ start_s = time.strftime(config.TV_TIMEFORMAT,
time.localtime(channels[0].programs[0].start))
+ stop_s = time.strftime(config.TV_TIMEFORMAT,
time.localtime(channels[0].programs[0].stop))
+ ts = '(%s-%s)' % (start_s, stop_s)
+ prog_info = '%s %s' % (ts, channels[0].programs[0].title)
+ else:
+ prog_info = channels[0].programs[0].title
else:
prog_info = 'No info'
Modified: branches/rel-1/freevo/src/tv/plugins/ivtv_xine_tv.py
==============================================================================
--- branches/rel-1/freevo/src/tv/plugins/ivtv_xine_tv.py (original)
+++ branches/rel-1/freevo/src/tv/plugins/ivtv_xine_tv.py Wed Oct 17
03:52:27 2007
@@ -12,13 +12,21 @@
# such as the Haupage PVR x50 series
#
# Todo:
-# - show OSD text once xine supports it
-#
http://sourceforge.net/tracker/index.php?func=detail&aid=1631022&group_id=9655&atid=359655
-# - skip to end of buffer on channel change
-#
http://sourceforge.net/tracker/index.php?func=detail&aid=1631019&group_id=9655&atid=359655
# - toggle between live and record mode
-# - implement progressive/accelerated seek mode
-# - implement vcr mode
+#
+# Dependencies
+# - Xine: [ 1810459 ] [Patch] Configurable OSD fonts
+#
http://sourceforge.net/tracker/index.php?func=detail&aid=1810459&group_id=9655&atid=359655
+# - Xine: [ 1814163 ] [Patch] Add SetPosition100%
+#
http://sourceforge.net/tracker/index.php?func=detail&aid=1814163&group_id=9655&atid=359655
+#
+# Changes:
+# - Changed code to conform to new debug style
+# - Stop confirmation: press STOP twice to return to menu
+# - Automatic jump: undo time shift on channel change
+# - OSD messges: volume and channel info
+# - Progressive seek: automatically increase speed
+# - Video groups: enable svideo and composite inputs
#
# -----------------------------------------------------------------------
#
@@ -57,39 +65,62 @@
import tv.epg_xmltv as epg
from event import *
+from config import *
from gui.AlertBox import AlertBox
from tv.channels import FreevoChannels
+DEBUG = config.DEBUG
+DDEBUG = 0
# guard important config variables
-if not config.XINE_TV_VO_DEV:
- config.XINE_TV_VO_DEV = config.XINE_VO_DEV
- _debug_("XINE_TV_VO_DEV set to config.XINE_VO_DEV")
-if not config.XINE_TV_AO_DEV:
- config.XINE_TV_AO_DEV = config.XINE_AO_DEV
- _debug_("XINE_TV_AO_DEV set to config.XINE_AO_DEV")
-
-if not config.TV_CHANNELS:
- _debug_("TV_CHANNELS is not configured!")
+if not hasattr(config, 'TV_CHANNELS'):
+ _debug_("TV_CHANNELS is not configured!", DERROR)
-if not config.MIXER_VOLUME_TV_IN:
- _debug_("MIXER_VOLUME_TV_IN is not configured!")
+if not hasattr(config, 'MIXER_MAJOR_CTRL'):
+ _debug_("MIXER_MAJOR_CTRL is not configured!", DERROR)
-if not config.MIXER_MAJOR_CTRL:
- _debug_("MIXER_MAJOR_CTRL is not configured!")
+if not hasattr(config, 'MIXER_VOLUME_TV_IN'):
+ config.MIXER_VOLUME_TV_IN = 50
+ _debug_("MIXER_VOLUME_TV_IN is not configured!", DWARNING)
-if not config.XINE_COMMAND:
+if not hasattr(config, 'XINE_COMMAND'):
config.XINE_COMMAND = "xine"
- _debug_("XINE_TV_CHANNELS is not configured!")
+ _debug_("XINE_TV_CHANNELS is not configured!", DWARNING)
-if not config.XINE_ARGS_DEF:
+if not hasattr(config, 'XINE_ARGS_DEF'):
config.XINE_ARGS_DEF = ""
- _debug_("XINE_ARGS_DEF is not configured!")
+ _debug_("XINE_ARGS_DEF is not configured!", DWARNING)
-if not config.XINE_TV_TIMESHIFT_FILEMASK:
+if not hasattr(config, 'XINE_TV_VO_DEV'):
+ config.XINE_TV_VO_DEV = config.XINE_VO_DEV
+ _debug_("XINE_TV_VO_DEV set to config.XINE_VO_DEV", DWARNING)
+
+if not hasattr(config, 'XINE_TV_AO_DEV'):
+ config.XINE_TV_AO_DEV = config.XINE_AO_DEV
+ _debug_("XINE_TV_AO_DEV set to config.XINE_AO_DEV", DWARNING)
+
+if not hasattr(config, 'XINE_TV_TIMESHIFT_FILEMASK'):
config.XINE_TV_TIMESHIFT_FILEMASK = "/tmp/xinebuf"
- _debug_("XINE_TV_TIMESHIFT_FILEMASK is not configured!")
+ _debug_("XINE_TV_TIMESHIFT_FILEMASK is not configured!", DWARNING)
+
+if not hasattr(config, 'XINE_TV_CONFIRM_STOP'):
+ config.XINE_TV_CONFIRM_STOP = True
+ _debug_("XINE_TV_CONFIRM_STOP is not configured!", DWARNING)
+
+if not hasattr(config, 'XINE_TV_PROGRESSIVE_SEEK'):
+ config.XINE_TV_PROGRESSIVE_SEEK = True
+ _debug_("XINE_TV_PROGRESSIVE_SEEK is not configured!", DWARNING)
+
+if config.XINE_TV_PROGRESSIVE_SEEK == True:
+ if not hasattr(config, 'XINE_TV_PROGRESSIVE_SEEK_THRESHOLD'):
+ config.XINE_TV_PROGRESSIVE_SEEK_THRESHOLD = 2
+ _debug_("XINE_TV_PROGRESSIVE_SEEK_THRESHOLD is not configured!",
DWARNING)
+
+ if not hasattr(config, 'XINE_TV_PROGRESSIVE_SEEK_INCREMENT'):
+ config.XINE_TV_PROGRESSIVE_SEEK_INCREMENT = 5
+ _debug_("XINE_TV_PROGRESSIVE_SEEK_INCREMENT is not configured!",
DWARNING)
+
class PluginInterface(plugin.Plugin):
"""
@@ -98,39 +129,161 @@
- Live TV: pause & continue, seek forward & backward
- Multiple digit channel selection: '1', '12, '123'
- Channel stack: jump to previously viewed channel
+ - Automatic jump: undo time shift on channel change
+ - OSD messges: volume and channel info
+ - Progressive seek: automatically increase seek speed
+ - Video groups: enable svideo and composite inputs
+ - Stop confirmation: press STOP twice to return to menu
+ =================================================================
Requirements:
- -------------
+ =================================================================
The following software must be installed:
- ivtv (e.g. Haupage x50 series TV card)
- xine (built with xvmc / xxmc if available)
+ =================================================================
Configuration:
- --------------
+ =================================================================
The following items should be configured in local_conf.py:
+ Freevo General Config Items
- TV_CHANNELS
- MIXER_VOLUME_TV_IN
- MIXER_MAJOR_CTRL
- XINE_COMMAND
- XINE_ARGS_DEF
+
+ Plugin Specific Config Items
- XINE_TV_VO_DEV
- XINE_TV_AO_DEV
- XINE_TV_TIMESHIFT_FILEMASK
+ - XINE_TV_CONFIRM_STOP
+ - XINE_TV_PROGRESSIVE_SEEK
+ - XINE_TV_PROGRESSIVE_SEEK_THRESHOLD
+ - XINE_TV_PROGRESSIVE_SEEK_INCREMENT
+
+ =================================================================
+ Plugin Specific Events
+ =================================================================
+ The following additional events can be defined:
+
+ # --local_conf.py:
+
+ # go back to the previous viewed channel
+ EVENTS['tv']['SOME_LIRC_CMD'] = Event('POPCHANNEL')
+
+ # show program info
+ EVENTS['tv']['SOME_LIRC_CMD'] = Event('TOGGLE_OSD')
+
+ # normal seek forward/backward by 1 second
+ EVENTS['tv']['SOME_LIRC_CMD'] = Event(SEEK, arg=-1)
+ EVENTS['tv']['SOME_LIRC_CMD'] = Event(SEEK, arg=+1)
+
+ =================================================================
+ Timeshift Filemask
+ =================================================================
+ The LIVE TV functionality requires a large buffer on disk
+ where the TV stream is being recorded while watching.
+
+ # --local_conf.py:
+
+ # This specifies the path and filemask that xine uses for
+ # timeshifting. File can get quite big (several gigabytes)
+ XINE_TV_TIMESHIFT_FILEMASK = "/local/tmp/xine-buf-!!20"
+
+ =================================================================
+ STOP Confirmation
+ =================================================================
+ The STOP event will cancel the history of the TV stream. To
+ prevent that this happens by accident, a confirmation can be
+ requested.
+
+ # --local_conf.py:
+
+ # Stop confirmation: press STOP twice to return to menu
+ XINE_TV_CONFIRM_STOP = True
+
+ =================================================================
+ Progressive Seek
+ =================================================================
+ If progressive is enabled, then seeking in the TV stream
+ will speed up by 'increment' seconds every 'threshold'
+ seconds. Note, set the starting seek event to 1 second to
+ allow fine control.
+
+ # --local_conf.py:
+
+ # This enables the progressive seek feature. The speed
+ # for seeking (fast forward and rewind) is increased
+ # automatically. The speed is increased every [THRESHOLD]
+ # seconds in steps of [INCREMENT] secnds.
+ XINE_TV_PROGRESSIVE_SEEK = True
+ XINE_TV_PROGRESSIVE_SEEK_THRESHOLD = 2
+ XINE_TV_PROGRESSIVE_SEEK_INCREMENT = 5
+
+ =================================================================
+ Video Groups Setup Example
+ =================================================================
+ The following shows an example of a configuration for a 1-tuner
+ PVR 250 card and adds S-VIDEO and Composite Inputs. Note that the
+ audio input is selected automatically by ivtv.
+
+ # --local_conf.py:
+
+ VIDEO_GROUPS = [
+ VideoGroup(
+ vdev='/dev/video0',
+ adev=None,
+ input_type='tuner',
+ input_num=0,
+ tuner_norm='pal',
+ tuner_chanlist='europe-west',
+ desc='Regular Cable',
+ group_type='ivtv',
+ record_group = None
+ ),
+ VideoGroup(
+ vdev='/dev/video0',
+ adev=None,
+ input_type='svideo',
+ input_num=1,
+ tuner_type='external',
+ desc='S-Video Input',
+ group_type='ivtv',
+ record_group = None
+ ),
+ VideoGroup(
+ vdev='/dev/video0',
+ adev=None,
+ input_type='composite',
+ input_num=5,
+ tuner_type='external',
+ desc='Composite Input',
+ group_type='ivtv',
+ record_group = None
+ ),
+ ]
+
+ TV_CHANNELS = [
+ ('ned1', 'NED 1', 'C22', '', 0),
+ ...
+ ('natg', 'National Geographic', 'C47', '', 0),
+ ...
+ ('svideo', 'S-Video Input', 'EX1', '', 1),
+ ('composite', 'Composite Input', 'EX2', '', 2),
+ ]
- To enable the channel stack, add the following event
- to local_conf.py:
-
- EVENTS['tv']['SOME_LIRC_CMD'] = Event('POPCHANNEL')
-
+ =================================================================
Refer to the config file for further explanation.
"""
__author__ = "Richard van Paasen"
__author_email__ = "[EMAIL PROTECTED]"
+
__maintainer__ = __author__
__maintainer_email__ = __author_email__
__version__ = "$Revision$"
@@ -149,6 +302,11 @@
Main class of the plugin
"""
+ #========================================================================
+ # __init__
+ # constructor
+ #========================================================================
+
def __init__(self):
self.xine = XineThread()
@@ -156,53 +314,108 @@
self.xine.start()
self.tuner = TunerControl()
+ self.tuner.setParent(self)
self.mixer = MixerControl()
self.app_mode = "tv"
self.app = None
self.videodev = None
- self.lastinput_value = None
self.lastinput_time = 0
+ self.lastinput_value = None
+
+ self.notahead = False
+ self.seeksteps = 0
+ self.seektime_start = 0
+ self.seektime_previous = 0
+ self.seekevent_previous = None
+
+ self.confirmstop_time = 0
+
+ #========================================================================
+ # Play
+ # start xine player
+ #========================================================================
def Play(self, mode, channel=None, channel_change=0):
- _debug_("IVTV_XINE_TV: Play channel = '%s'" % channel)
+ _debug_("IVTV_XINE_TV: Play channel = '%s'" % channel, DDEBUG)
self.mode = mode
self.prev_app = rc.app()
rc.app(self)
- self.tuner.SetChannel(channel, True)
self.mixer.prepare()
+ self.tuner.SetChannel(channel, True)
self.xine.play()
# Suppress annoying audio clicks
time.sleep(0.6)
self.mixer.start()
- _debug_("IVTV_XINE_TV: Started '%s' app" % self.mode)
+ _debug_("IVTV_XINE_TV: Started '%s' app" % self.mode, DDEBUG)
- def Pause(self):
+ #========================================================================
+ # Stop
+ # stop xine player
+ #========================================================================
- self.xine.pause()
+ def Stop(self):
+ confirmstop_time = int(time.time())
+ # note: the OSD msg is displayed for 5 seconds
+ if (config.XINE_TV_CONFIRM_STOP == True) and (confirmstop_time -
self.confirmstop_time > 4):
+ self.ShowMessage("Please repeat to stop\n")
+ self.confirmstop_time = confirmstop_time
+ else:
+ self.mixer.stop()
+ self.xine.stop()
+ rc.app(self.prev_app)
+ rc.post_event(PLAY_END)
+ _debug_("IVTV_XINE_TV: Stopped '%s' app" % self.mode, DDEBUG)
+
+
+ #========================================================================
+ # ShowMessage
+ # show a message on the OSD
+ #========================================================================
+
+ def ShowMessage(self, msg):
+
+ _debug_("IVTV_XINE_TV: Show OSD Message: '%s'" % msg, DDEBUG)
+ self.xine.write("OSDWriteText$%s\n" % msg)
- def Stop(self):
- self.mixer.stop()
- self.xine.stop()
- rc.app(self.prev_app)
- rc.post_event(PLAY_END)
- _debug_("IVTV_XINE_TV: Stopped '%s' app" % self.mode)
+ #========================================================================
+ # SeekEnd
+ # Skip to end of stream
+ # The notahead flag indicates if the user has used the pause or rewind
+ # buttons. That implies that the seek is needed.
+ #========================================================================
+
+ def SeekEnd(self):
+
+ if self.notahead == True:
+ _debug_("IVTV_XINE_TV: Executing SeekEnd", DDEBUG)
+
+ self.xine.write("SetPosition100%\n")
+ self.notahead = False
+
+ else:
+ _debug_("IVTV_XINE_TV: SeekEnd not needed", DDEBUG)
+ #========================================================================
+ # eventhandler
+ # freevo eventhandler
+ #========================================================================
+
def eventhandler(self, event, menuw=None):
- _debug_("IVTV_XINE_TV: '%s' app got '%s' event" % (self.mode, event))
+ _debug_("IVTV_XINE_TV: '%s' app got '%s' event" % (self.mode, event),
DDEBUG)
s_event = "%s" % event
@@ -214,7 +427,8 @@
if event == PAUSE or event == PLAY:
- self.Pause()
+ self.xine.pause()
+ self.notahead = True
return True
@@ -239,14 +453,17 @@
else:
eventInput=s_event[6]
isNumeric=TRUE
+
try:
newinput_value = int(eventInput)
except:
#Protected against INPUT_UP, INPUT_DOWN, etc
isNumeric=FALSE
+
if isNumeric:
# tune explicit channel
newinput_time = int(time.time())
+
if (self.lastinput_value != None):
# allow 2 seconds delay for multiple digit channels
if (newinput_time - self.lastinput_time < 2):
@@ -254,55 +471,84 @@
if (self.lastinput_value >= 100):
self.lastinput_value = (self.lastinput_value %
100)
newinput_value = self.lastinput_value * 10 +
newinput_value
+
self.lastinput_value = newinput_value
self.lastinput_time = newinput_time
- self.tuner.TuneChannelByNumber(newinput_value)
+ self.tuner.TuneChannelByIndex(newinput_value)
+
if newinput_value > 9:
# cancel intermediate channels
self.tuner.UnpushChannel()
+
return True
if event == SEEK:
- steps = int(event.arg)
+ seeksteps = int(event.arg)
- if steps == 0:
+ if seeksteps == 0:
- _debug_("IVTV_XINE_TV: Ignoring seek 0")
+ _debug_("IVTV_XINE_TV: Ignoring seek 0", DDEBUG)
return True
- if steps < 0:
+ if seeksteps < 0:
action = "SeekRelative-"
- steps = 0 - steps
+ seeksteps = 0 - seeksteps
+ self.notahead = True
else:
action = "SeekRelative+"
- # seeking can only be done in steps of 7, 15, 30 or 60
+ if config.XINE_TV_PROGRESSIVE_SEEK:
- if steps <= 7:
- steps = 7
- elif steps <= 15:
- steps = 15
- elif steps <= 30:
- steps = 30
- else:
- steps = 60
+ seekevent_current = event.arg
+ seeksteps_current = seeksteps
+ seektime_current = int(time.time())
+ seektime_delta = seektime_current - self.seektime_previous
+
+ if (seektime_delta > 2) or (seekevent_current !=
self.seekevent_previous):
+ # init/reset progressive seek mode
+ self.seeksteps = seeksteps
+ self.seektime_start = seektime_current
+ self.seektime_previous = seektime_current
+ else:
+ # continue progressive
+ if (
+ (seektime_delta > 0) and
+ ((seektime_delta %
config.XINE_TV_PROGRESSIVE_SEEK_THRESHOLD) == 0)
+ ):
+ self.seeksteps +=
config.XINE_TV_PROGRESSIVE_SEEK_INCREMENT
+ self.seektime_previous = seektime_current
+
+ self.seekevent_previous = seekevent_current
+ seeksteps = self.seeksteps
+
+ # Note: Xine 2007 versions support
+ # arbitrary SeekRelative+/- steps
+ # limit seeksteps to [1 ; 120] seconds
+ seeksteps = min( max(1, seeksteps), 120 )
- _debug_("IVTV_XINE_TV: Seeking '%s%s' seconds" % (action, steps))
+ _debug_("IVTV_XINE_TV: Seeking '%s%s' seconds" % (action,
seeksteps), DDEBUG)
- self.xine.app.write("%s%s\n" % (action, steps))
+ self.xine.write("%s#%s\n" % (action, seeksteps))
return True
if event == TOGGLE_OSD:
- self.xine.app.write("OSDStreamInfos\n")
+ self.tuner.ShowInfo()
+
+ return True
+
+
+ if event == OSD_MESSAGE:
+
+ self.ShowMessage(event.arg)
return True
@@ -315,6 +561,11 @@
Class that controls the tuner device
"""
+ #========================================================================
+ # __init__
+ # constructor
+ #========================================================================
+
def __init__(self):
self.ivtv_init = False
@@ -324,6 +575,11 @@
self.stack = [ ]
+ #========================================================================
+ # __kill__
+ # destructor
+ #========================================================================
+
def _kill_(self):
if self.embed:
@@ -331,46 +587,93 @@
ivtv_dev.setvbiembed(self.embed)
+ #========================================================================
+ # ShowInfo
+ # show channle info
+ #========================================================================
+
+ def ShowInfo(self):
+
+ # show channel info
+ vg = self.fc.getVideoGroup(self.curr_channel, True)
+ if vg.input_type == 'tuner':
+ tuner_id, chan_name, prog_info =
self.fc.getChannelInfo(showtime=False)
+ msg = "%s: %s" % (chan_name, prog_info)
+ self.parent.ShowMessage("%s" % msg)
+ else:
+ # show channel info
+ self.parent.ShowMessage(vg.desc)
+
+ #========================================================================
+ # setParent
+ # keep a reference to the IVTV_XINE_TV object
+ #========================================================================
+
+ def setParent(self, parent):
+
+ self.parent = parent
+
+
+ #========================================================================
+ # PushChannel
+ # push the current channel on the channel stack
+ #========================================================================
+
def PushChannel(self):
if self.curr_channel != None:
self.stack.append(self.curr_channel)
- _debug_("TunerControl: Pushed channel %s" % self.curr_channel)
+ _debug_("TunerControl: Pushed channel %s" % self.curr_channel,
DDEBUG)
+
+ _debug_("TunerControl: Channel stack = %s" % self.stack, DDEBUG)
- _debug_("TunerControl: Channel stack = %s" % self.stack)
+ #========================================================================
+ # UnpushChannel
+ # remove the top channel fromthe channel stack
+ #========================================================================
def UnpushChannel(self):
if len(self.stack) == 0:
- _debug_("TunerControl: Channel stack is empty")
+ _debug_("TunerControl: Channel stack is empty", DDEBUG)
else:
channel = self.stack.pop()
- _debug_("TunerControl: Unpushed channel %s" % channel)
+ _debug_("TunerControl: Unpushed channel %s" % channel, DDEBUG)
+
+ _debug_("TunerControl: Channel stack = %s" % self.stack, DDEBUG)
- _debug_("TunerControl: Channel stack = %s" % self.stack)
+ #========================================================================
+ # PopChannel
+ # pop the top channel from the channel stack and switch channel
+ #========================================================================
def PopChannel(self):
if len(self.stack) == 0:
- _debug_("TunerControl: Channel stack is empty")
+ _debug_("TunerControl: Channel stack is empty", DDEBUG)
else:
channel = self.stack.pop()
- _debug_("TunerControl: Popped channel %s" % channel)
+ _debug_("TunerControl: Popped channel %s" % channel, DDEBUG)
self.SetVideoGroup(channel)
- _debug_("TunerControl: Channel stack = %s" % self.stack)
+ _debug_("TunerControl: Channel stack = %s" % self.stack, DDEBUG)
+ #========================================================================
+ # SetChannel
+ # select a new channel
+ #========================================================================
+
def SetChannel(self, channel=None, clearstack=False):
# set channel by name
@@ -410,67 +713,86 @@
if (next_channel == None):
- _debug_("TunerControl: Cannot find tuner channel '%s' in the TV
channel listing" % channel)
+ _debug_("TunerControl: Cannot find tuner channel '%s' in the TV
channel listing" % channel, DWARNING)
else:
self.TuneChannelByIndex(channel_index + 1)
+ #========================================================================
+ # TuneChannelByIndex
+ # tune to a channel by index from the TV_CHANNELS list
+ #========================================================================
+
def TuneChannelByIndex(self, channel):
# tune channel by index
-
next_channel = self.fc.getManChannel(channel)
- _debug_("TunerControl: Explicit channel selection = '%s'" %
next_channel)
+ _debug_("TunerControl: Explicit channel selection = '%s'" %
next_channel, DDEBUG)
self.PushChannel()
self.SetVideoGroup(next_channel)
- def TuneChannelByNumber(self, channel):
-
- # tune channel by number
-
- self.PushChannel()
- self.SetVideoGroup(str(channel))
+ #========================================================================
+ # NextChannel
+ # jump to the next channel in the TV_CHANNELS list
+ #========================================================================
def NextChannel(self):
next_channel = self.fc.getNextChannel()
- _debug_("TunerControl: Next channel selection = '%s'" % next_channel)
+ _debug_("TunerControl: Next channel selection = '%s'" % next_channel,
DDEBUG)
self.PushChannel()
self.SetVideoGroup(next_channel)
+ #========================================================================
+ # PrevChannel
+ # jump to the previous channel in the TV)CHANNELS list
+ #========================================================================
+
def PrevChannel(self):
prev_channel = self.fc.getPrevChannel()
- _debug_("TunerControl: Previous channel selection = '%s'" %
prev_channel)
+ _debug_("TunerControl: Previous channel selection = '%s'" %
prev_channel, DDEBUG)
self.PushChannel()
self.SetVideoGroup(prev_channel)
+ #========================================================================
+ # SetVideoGroup
+ # select a channel's video group and tune to that channel
+ #========================================================================
+
def SetVideoGroup(self, channel):
- _debug_("TunerControl: Play channel = '%s'" % channel)
- vg = self.fc.getVideoGroup(channel, True)
- _debug_("TunerControl: Play group = '%s'" % vg.desc)
+ _debug_("TunerControl: Channel: '%s'" % channel, DDEBUG)
+ new_vg = self.fc.getVideoGroup(channel, True)
+ _debug_("TunerControl: Group: 'type=%s, desc=%s'" %
(new_vg.group_type, new_vg.desc), DDEBUG)
+ _debug_("TunerControl: Input: 'type=%s, num=%s'" % (new_vg.input_type,
new_vg.input_num), DDEBUG)
- if (vg.group_type != "ivtv"):
+ if (new_vg.group_type != "ivtv"):
- _debug_("TunerControl: Video group '%s' is not supported" %
vg.group_type)
- pop = AlertBox(text=_("This plugin only supports the ivtv video
group in tv mode!"))
+ _debug_("TunerControl: Video group '%s' is not supported" %
new_vg.group_type, DERROR)
+ pop = AlertBox(text=_("This plugin only supports the ivtv video
group!"))
pop.show()
return
- if self.ivtv_init == False:
+ # check if videogroup switch is needed
+ switch_vg = (self.ivtv_init == False) or \
+ (self.curr_channel == None) or \
+ (new_vg != self.fc.getVideoGroup(self.curr_channel, True))
- ivtv_dev = ivtv.IVTV(vg.vdev)
+ if switch_vg == True:
+
+ # switch to a different video group
+ ivtv_dev = ivtv.IVTV(new_vg.vdev)
ivtv_dev.init_settings()
- ivtv_dev.setinput(vg.input_num)
+ ivtv_dev.setinput(new_vg.input_num)
ivtv_dev.print_settings()
# disable embedded vbi data
@@ -479,17 +801,11 @@
self.ivtv_init = True
+ # set channel
self.fc.chanSet(channel, True)
self.curr_channel = channel
-
- # todo: skip to end of stream
- # todo: insert xine OSD message here ...
-
- # tuner_id, chan_name, prog_info = self.fc.getChannelInfo()
- # now = time.strftime(config.TV_TIMEFORMAT)
- # msg = "%s %s (%s): %s" % (now, chan_name, tuner_id, prog_info)
- # cmd = "osd_show_text '%s'\n" % msg
- # todo: insert xine OSD message here ...
+ self.ShowInfo()
+ self.parent.SeekEnd()
# ======================================================================
@@ -500,12 +816,22 @@
Class that controls the mixer device
"""
+ #========================================================================
+ # __init__
+ # constructor
+ #========================================================================
+
def __init__(self):
self.mixer = plugin.getbyname("MIXER")
self.volume = 0
+ #========================================================================
+ # prepare
+ # turn down volume
+ #========================================================================
+
def prepare(self):
if (self.mixer != None):
@@ -521,6 +847,11 @@
self.mixer.setPcmVolume(0)
+ #========================================================================
+ # start
+ # turn up volume
+ #========================================================================
+
def start(self):
if (self.mixer != None):
@@ -537,6 +868,11 @@
self.mixer.setPcmVolume(self.volume)
+ #========================================================================
+ # stop
+ # turn down volume
+ #========================================================================
+
def stop(self):
if (self.mixer != None):
@@ -554,22 +890,32 @@
Class that controls the Xine process
"""
+ #========================================================================
+ # __init__
+ # constructor
+ #========================================================================
+
def __init__(self, app, item):
self.item = item
- _debug_("XineApp: Starting xine, cmd = '%s'" % app)
+ _debug_("XineApp: Starting xine, cmd = '%s'" % app, DDEBUG)
childapp.ChildApp2.__init__(self, app)
self.exit_type = None
self.done = False
+ #========================================================================
+ # __kill__
+ # destructor
+ #========================================================================
+
def _kill_(self):
- _debug_("XineApp: Killing xine...")
+ _debug_("XineApp: Killing xine...", DDEBUG)
childapp.ChildApp2.kill(self,signal.SIGTERM)
self.done = True
-# ======================================================================
+#========================================================================
class XineThread(threading.Thread):
@@ -577,6 +923,11 @@
Thread that handles Xine commands
"""
+ #========================================================================
+ # __init__
+ # constructor
+ #========================================================================
+
def __init__(self):
threading.Thread.__init__(self)
@@ -596,15 +947,15 @@
xinecmd = ""
self.fbxine = False
- _debug_( "XineThread: configuration overview" )
- _debug_( " config.CONF.xine = '%s'" % (config.CONF.xine) )
- _debug_( " config.XINE_COMMAND = '%s'" % (config.XINE_COMMAND) )
- _debug_( " config.XINE_ARGS_DEF = '%s'" % (config.XINE_ARGS_DEF) )
- _debug_( " config.XINE_TV_VO_DEV = '%s'" % (config.XINE_TV_VO_DEV) )
- _debug_( " config.XINE_TV_AO_DEV = '%s'" % (config.XINE_TV_AO_DEV) )
- _debug_( " config.XINE_TV_TIMESHIFT_FILEMASK = '%s'" %
(config.XINE_TV_TIMESHIFT_FILEMASK) )
- _debug_( " effective xinecmd = '%s'" % (xinecmd) )
- _debug_( " effective self.fbxine = '%s'" % (self.fbxine) )
+ _debug_("XineThread: configuration overview", DDEBUG)
+ _debug_(" config.CONF.xine = '%s'" % (config.CONF.xine), DDEBUG)
+ _debug_(" config.XINE_COMMAND = '%s'" % (config.XINE_COMMAND),
DDEBUG)
+ _debug_(" config.XINE_ARGS_DEF = '%s'" % (config.XINE_ARGS_DEF),
DDEBUG)
+ _debug_(" config.XINE_TV_VO_DEV = '%s'" % (config.XINE_TV_VO_DEV),
DDEBUG)
+ _debug_(" config.XINE_TV_AO_DEV = '%s'" % (config.XINE_TV_AO_DEV),
DDEBUG)
+ _debug_(" config.XINE_TV_TIMESHIFT_FILEMASK = '%s'" %
(config.XINE_TV_TIMESHIFT_FILEMASK), DDEBUG)
+ _debug_(" effective xinecmd = '%s'" % (xinecmd), DDEBUG)
+ _debug_(" effective self.fbxine = '%s'" % (self.fbxine), DDEBUG)
if self.fbxine:
@@ -618,6 +969,23 @@
config.XINE_TV_AO_DEV, config.XINE_TV_TIMESHIFT_FILEMASK)
+ #========================================================================
+ # write
+ # send a command to the xine player
+ #========================================================================
+
+ def write(self, msg):
+
+ if self.state != "idle":
+
+ self.app.write(msg)
+
+
+ #========================================================================
+ # play
+ # start playing
+ #========================================================================
+
def play(self):
if self.state == "idle":
@@ -625,6 +993,11 @@
self.start_flag.set()
+ #========================================================================
+ # pause
+ # pause playing
+ #========================================================================
+
def pause(self):
if self.state == "busy":
@@ -632,6 +1005,11 @@
self.state = "pause"
+ #========================================================================
+ # stop
+ # stop playing
+ #========================================================================
+
def stop(self):
if self.state == "busy":
@@ -642,12 +1020,17 @@
while not self.app.done:
- _debug_("XineThread: Waiting for xine to end...")
+ _debug_("XineThread: Waiting for xine to end...", DDEBUG)
time.sleep(0.1)
- _debug_("XineThread: Xine ended")
+ _debug_("XineThread: Xine ended", DDEBUG)
+ #========================================================================
+ # run
+ # worker method
+ #========================================================================
+
def run(self):
while 1:
@@ -659,7 +1042,7 @@
else:
- _debug_("XineThread: Should be idle on thread entry!")
+ _debug_("XineThread: Should be idle on thread entry!",
DWARNING)
self.app = XineApp(self.command, self.item)
self.state = "busy"
@@ -670,7 +1053,7 @@
if laststate != self.state:
- _debug_("XineThread: state '%s' -> '%s'" % (laststate,
self.state))
+ _debug_("XineThread: state '%s' -> '%s'" % (laststate,
self.state), DDEBUG)
laststate = self.state
if self.state == "busy":
@@ -684,20 +1067,21 @@
elif self.state == "stop":
- _debug_("XineThread: Stoppping xine")
+ _debug_("XineThread: Stoppping xine", DDEBUG)
self.app.stop("quit\n")
if self.fbxine:
- # directfb needs xine to be killed
- # else the display is messed up
- # and freevo crashes
+ # directfb needs xine to be killed
+ # else the display is messed up
+ # and freevo crashes
+
time.sleep(1.0)
- _debug_("XineThread: Killing xine")
+ _debug_("XineThread: Killing xine", DDEBUG)
self.app._kill_()
self.state = "busy"
- _debug_("XineThread: Stopped")
+ _debug_("XineThread: Stopped", DDEBUG)
self.state = 'idle'
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog