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

Reply via email to