Update of /cvsroot/freevo/kaa/mplayer/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1658
Modified Files:
__init__.py
Log Message:
Make how we gather information from mplayer binary smarter; make things
more asynchronous.
Index: __init__.py
===================================================================
RCS file: /cvsroot/freevo/kaa/mplayer/src/__init__.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** __init__.py 2 Aug 2005 14:23:52 -0000 1.2
--- __init__.py 2 Aug 2005 19:56:32 -0000 1.3
***************
*** 1,3 ****
! import os, re, string, tempfile, time
from kaa import notifier, display
--- 1,3 ----
! import os, re, string, tempfile, time, stat
from kaa import notifier, display
***************
*** 7,13 ****
--- 7,89 ----
DEBUG=0
+ # A cache holding values specific to an MPlayer executable (version,
+ # filter list, video/audio driver list, input keylist). This dict is
+ # keyed on the full path of the MPlayer binary.
+ _cache = {}
+
+ def _get_mplayer_info(path, mtime = None):
+ """
+ Fetches info about the given MPlayer executable. If the values are
+ cached and the cache is fresh, it returns a dict immediately. If it
+ needs to load MPlayer to fetch the values, it returns a Signal object
+ that the caller can connect to to receive the result once it's complete.
+ The value passed to the signal callback is either the values dict, or an
+ Exception object if an error occurred.
+
+ If 'mtime' is not None, it means we've called ourself as a thread.
+ """
+
+ if not mtime:
+ # Fetch the mtime of the binary
+ mtime = os.stat(path)[stat.ST_MTIME]
+
+ if path in _cache and _cache[path]["mtime"] == mtime:
+ # Cache isn't stale, so return that.
+ return _cache[path]
+
+ # We need to run MPlayer to get these values. Create a signal, call
+ # ourself as a thread, and return the signal back to the caller.
+ signal = notifier.Signal()
+ thread = notifier.Thread(_get_mplayer_info, path, mtime)
+ # Thread class ensures the callbacks get invoked in the main thread.
+ thread.signals["completed"].connect(signal.emit)
+ thread.signals["exception"].connect(signal.emit)
+ thread.start()
+ return signal
+
+ # At this point we're running in a thread.
+
+ info = {
+ "version": None,
+ "mtime": mtime,
+ "video_filters": {},
+ "video_drivers": {},
+ "audio_filters": {},
+ "audio_drivers": {},
+ "keylist": []
+ }
+
+ regexps = (
+ ("video_filters", "-vf help", "\s*(\w+)\s+:\s+(.*)"),
+ ("video_drivers", "-vo help", "\s*(\w+)\s+(.*)"),
+ ("audio_filters", "-af help", "\s*(\w+)\s+:\s+(.*)"),
+ ("audio_drivers", "-ao help", "\s*(\w+)\s+(.*)"),
+ ("keylist", "-input keylist", "^(\w+)$"),
+ )
+
+ for key, args, regexp in regexps:
+ for line in os.popen("%s %s" % (path, args)):
+ # Check version
+ if line.startswith("MPlayer "):
+ info["version"] = line.split()[1]
+
+ # Check regexp
+ m = re.match(regexp, line.strip())
+ if not m:
+ continue
+
+ if len(m.groups()) == 2:
+ info[key][m.group(1)] = m.group(2)
+ else:
+ info[key].append(m.group(1))
+
+ _cache[path] = info
+ return info
+
+
class MPlayerError(Exception):
pass
+
class MPlayer(object):
***************
*** 19,22 ****
--- 95,102 ----
STATE_PLAYING = 2
STATE_PAUSED = 3
+ # Waiting for some operation to complete before playing a video;
+ # state_data contains a tuple (filename, user_args) that should be played
+ # when the operation is finished.
+ STATE_PENDING = 4
RE_STATUS = re.compile("A:\s*([\d+\.]+)|V:\s*([\d+\.]+)")
***************
*** 49,55 ****
self._process = None
self._state = MPlayer.STATE_EXITED
! self.filters = {}
! self.info = {}
self._position = 0.0
--- 129,135 ----
self._process = None
self._state = MPlayer.STATE_EXITED
+ self._state_data = None
! self._file_info = {}
self._position = 0.0
***************
*** 65,86 ****
}
! mp = self._spawn("-vf help", hook_notifier = False)
! valid = False
! for line in mp.readlines():
! if line[:7] == "MPlayer":
! valid = True
! m = re.match("\s*(\w+)\s+:\s+(.*)", line)
! if m:
! self.filters[m.group(1)] = m.group(2)
!
! if not valid:
! raise MPlayerError, "'%s' doesn't seem to be a valid MPlayer" %
self._mp_cmd
!
! self._keylist = []
! mp = self._spawn("-input keylist", hook_notifier = False)
! for line in mp.readlines():
! if line.find(" ") == -1 and line:
! self._keylist.append(line)
!
--- 145,152 ----
}
! self._mp_info = _get_mplayer_info(self._mp_cmd)
! if type(self._mp_info) == notifier.Signal:
! self._mp_info.connect(self._handle_mp_info)
! self._mp_info = None
***************
*** 105,109 ****
"""
keys = filter(lambda x: x not in string.whitespace, string.printable)
! keys = list(keys) + self._keylist
fp, filename = tempfile.mkstemp()
for key in keys:
--- 171,175 ----
"""
keys = filter(lambda x: x not in string.whitespace, string.printable)
! keys = list(keys) + self._mp_info["keylist"]
fp, filename = tempfile.mkstemp()
for key in keys:
***************
*** 112,118 ****
return filename
def _handle_line(self, line):
-
if line[:2] in ("A:", "V:"):
m = MPlayer.RE_STATUS.match(line)
--- 178,193 ----
return filename
+ def _handle_mp_info(self, info):
+ if isinstance(info, Exception):
+ # TODO: handle me
+ raise info
+ self._mp_info = info
+ if self._state == MPlayer.STATE_PENDING:
+ file, user_args = self._state_data
+ self._state_data = None
+ self._play(file, user_args)
+
def _handle_line(self, line):
if line[:2] in ("A:", "V:"):
m = MPlayer.RE_STATUS.match(line)
***************
*** 144,153 ****
"FILENAME": ("filename", str) }
if attr in info:
! self.info[info[attr][0]] = info[attr][1](value)
elif line.startswith("Movie-Aspect"):
aspect = line[16:].split(":")[0].replace(",", ".")
if aspect[0].isdigit():
! self.info["aspect"] = float(aspect)
elif line.startswith("VO:"):
--- 219,228 ----
"FILENAME": ("filename", str) }
if attr in info:
! self._file_info[info[attr][0]] = info[attr][1](value)
elif line.startswith("Movie-Aspect"):
aspect = line[16:].split(":")[0].replace(",", ".")
if aspect[0].isdigit():
! self._file_info["aspect"] = float(aspect)
elif line.startswith("VO:"):
***************
*** 186,189 ****
--- 261,289 ----
+ def _play(self, file, user_args = ""):
+ assert(self._mp_info)
+
+ keyfile = self._make_dummy_input_config()
+
+ filters = []
+ if self._size:
+ w, h = self._size
+ filters += ["scale=%d:-2" % w, "expand=%d:%d" % (w, h)]
+
+ filters += ["expand=:::::.891"]
+ args = "-v -slave -osdlevel 0 -nolirc -nojoystick -nomouseinput " \
+ "-nodouble -fixed-vo -identify -framedrop -input conf=%s " %
keyfile
+
+ if filters:
+ args += "-vf %s " % string.join(filters, ",")
+
+ args += "-wid %s " % self._window.get_id()
+ args += "-display %s " % self._window.get_display().get_string()
+ args += "%s \"%s\" " % (user_args, file)
+
+ self._spawn(args)
+ self._state = MPlayer.STATE_LOADING
+
+
def _slave_cmd(self, cmd):
self._process.write(cmd + "\n")
***************
*** 206,229 ****
self._window = display.X11Window(size = win_size, title =
"MPlayer Window")
! keyfile = self._make_dummy_input_config()
!
! filters = []
! if self._size:
! w, h = self._size
! filters += ["scale=%d:-2" % w, "expand=%d:%d" % (w, h)]
!
! args = "-v -slave -osdlevel 0 -nolirc -nojoystick -nomouseinput " \
! "-nodouble -fixed-vo -identify -input conf=%s " % keyfile
!
! if filters:
! args += "-vf %s " % string.join(filters, ",")
!
! args += "-wid %s " % self._window.get_id()
! args += "-display %s " % self._window.get_display().get_string()
! args += "%s \"%s\" " % (user_args, file)
!
! self._spawn(args)
! self._state = MPlayer.STATE_LOADING
def is_paused(self):
--- 306,322 ----
self._window = display.X11Window(size = win_size, title =
"MPlayer Window")
! if not self._mp_info:
! # We're probably waiting for _get_mplayer_info() to finish; set
! # state so that _handle_mp_info() will call _play(). There's no
! # race condition here if we're currently in the main thread,
! # because _handle_mp_info() is guaranteed to be called in the
! # main thread.
! self._state = MPlayer.STATE_PENDING
! self._state_data = (file, user_args)
! return False
+ self._play(file, user_args)
+ return True
+
def is_paused(self):
***************
*** 277,278 ****
--- 370,374 ----
def get_position(self):
return self._position
+
+ def get_file_info(self):
+ return self._file_info
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog