python-ctypes: implement support for callbacks
authorOlivier Aubert <olivier.aubert@liris.cnrs.fr>
Mon, 3 Aug 2009 15:07:06 +0000 (17:07 +0200)
committerOlivier Aubert <olivier.aubert@liris.cnrs.fr>
Mon, 3 Aug 2009 15:19:56 +0000 (17:19 +0200)
Makefile
TODO
footer.py [new file with mode: 0644]
generate.py
header.py
override.py

index 0bee51b..760bb9c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ MODULE_NAME=vlc.py
 
 all: $(MODULE_NAME)
 
-$(MODULE_NAME): generate.py header.py override.py ../../include/vlc/*.h
+$(MODULE_NAME): generate.py header.py footer.py override.py ../../include/vlc/*.h
        ./generate.py ../../include/vlc/*.h > $@
 
 doc: $(MODULE_NAME)
diff --git a/TODO b/TODO
index eab5b13..087d87b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,7 +1,5 @@
 * Investigate memory management
 
-* Implement event callbacks
-
 * Write a test suite
 
 * Support multiple VLC versions: define a front-end module which will
diff --git a/footer.py b/footer.py
new file mode 100644 (file)
index 0000000..b336629
--- /dev/null
+++ b/footer.py
@@ -0,0 +1,53 @@
+# Footer code.
+
+class MediaEvent(ctypes.Structure):
+    _fields_ = [
+        ('media_name', ctypes.c_char_p),
+        ('instance_name', ctypes.c_char_p),
+        ]
+
+class EventUnion(ctypes.Union):
+    _fields_ = [
+        ('meta_type', ctypes.c_uint),
+        ('new_child', ctypes.c_uint),
+        ('new_duration', ctypes.c_longlong),
+        ('new_status', ctypes.c_int),
+        ('media', ctypes.c_void_p),
+        ('new_state', ctypes.c_uint),
+        # Media instance
+        ('new_position', ctypes.c_float),
+        ('new_time', ctypes.c_longlong),
+        ('new_title', ctypes.c_int),
+        ('new_seekable', ctypes.c_longlong),
+        ('new_pausable', ctypes.c_longlong),
+        # FIXME: Skipped MediaList and MediaListView...
+        ('filename', ctypes.c_char_p),
+        ('new_length', ctypes.c_longlong),
+        ('media_event', MediaEvent),
+        ]
+
+class Event(ctypes.Structure):
+    _fields_ = [
+        ('type', EventTypeT),
+        ('object', ctypes.c_void_p),
+        ('u', EventUnion),
+        ]
+
+# Decorator for callback methods
+callbackmethod=ctypes.CFUNCTYPE(None, Event, ctypes.c_void_p)
+
+# Example callback method
+@callbackmethod
+def debug_callback(event, data):
+    print "Debug callback method"
+    print "Event:", event
+    print "Data", data
+
+if __name__ == '__main__':
+    import sys
+    if sys.argv[1:]:
+        i=vlc.Instance()
+        m=i.media_new(sys.argv[1])
+        p=MediaPlayer()
+        p.set_media(m)
+        p.play()
index d3b5d23..a5eb7ea 100755 (executable)
@@ -59,13 +59,13 @@ blacklist=[
     "libvlc_exception_get_message",
     "libvlc_get_vlc_instance",
 
-    "libvlc_media_add_option_flag",
     "libvlc_media_list_view_index_of_item",
     "libvlc_media_list_view_insert_at_index",
     "libvlc_media_list_view_remove_at_index",
     "libvlc_media_list_view_add_item",
 
     # In svn but not in current 1.0.0
+    "libvlc_media_add_option_flag",
     'libvlc_video_set_deinterlace',
     'libvlc_video_get_marquee_option_as_int',
     'libvlc_video_get_marquee_option_as_string',
@@ -74,10 +74,6 @@ blacklist=[
     'libvlc_vlm_get_event_manager',
 
     'mediacontrol_PlaylistSeq__free',
-
-    # TODO
-    "libvlc_event_detach",
-    "libvlc_event_attach",
     ]
 
 # Precompiled regexps
@@ -106,7 +102,7 @@ typ2class={
     'libvlc_log_t*': 'Log',
     'libvlc_log_iterator_t*': 'LogIterator',
     'libvlc_log_message_t*': 'LogMessage',
-    'libvlc_event_type_t': 'EventType',
+    'libvlc_event_type_t': 'ctypes.c_uint',
     'libvlc_event_manager_t*': 'EventManager',
     'libvlc_media_discoverer_t*': 'MediaDiscoverer',
     'libvlc_media_library_t*': 'MediaLibrary',
@@ -134,7 +130,7 @@ typ2class={
     'unsigned': 'ctypes.c_uint',
     'int': 'ctypes.c_int',
     '...': 'FIXMEva_list',
-    'libvlc_callback_t': 'FIXMEcallback',
+    'libvlc_callback_t': 'ctypes.c_void_p',
     'libvlc_time_t': 'ctypes.c_longlong',
     }
 
@@ -147,7 +143,6 @@ defined_classes=(
     'Log',
     'LogIterator',
     #'LogMessage',
-    'EventType',
     'EventManager',
     'MediaDiscoverer',
     'MediaLibrary',
@@ -157,9 +152,6 @@ defined_classes=(
     'TrackDescription',
     'AudioOutput',
     'MediaControl',
-    #'RGBPicture',
-    #'MediaControlPosition',
-    #'MediaControlStreamInformation',
     )
 
 # Definition of prefixes that we can strip from method names when
@@ -195,10 +187,10 @@ def parse_param(s):
         # K&R definition: only type
         return s.replace(' ', ''), ''
 
-def generate_header(classes=None):
-    """Generate header code.
+def insert_code(filename):
+    """Generate header/footer code.
     """
-    f=open('header.py', 'r')
+    f=open(filename, 'r')
     for l in f:
         if 'build_date' in l:
             print 'build_date="%s"' % time.ctime()
@@ -603,11 +595,12 @@ if __name__ == '__main__':
     if debug:
         sys.exit(0)
 
-    generate_header()
+    insert_code('header.py')
     generate_enums(enums)
     wrapped=generate_wrappers(methods)
     for l in methods:
         output_ctypes(*l)
+    insert_code('footer.py')
 
     all=set( t[1] for t in methods )
     not_wrapped=all.difference(wrapped)
index f4a2c2d..840bb33 100755 (executable)
--- a/header.py
+++ b/header.py
@@ -86,6 +86,9 @@ class LogMessage(ctypes.Structure):
                 ('message', ctypes.c_char_p),
                 ]
 
+    def __str__(self):
+        print "vlc.LogMessage(%d:%s): %s" % (self.severity, self.type, self.message)
+
 class MediaControlPosition(ctypes.Structure):
     _fields_= [
                 ('origin', ctypes.c_ushort),
@@ -142,9 +145,6 @@ class RGBPicture(ctypes.Structure):
     def free(self):
         mediacontrol_RGBPicture__free(self)
 
-# Decorator for callback methods
-callbackmethod=ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
-
 def check_vlc_exception(result, func, args):
     """Error checking method for functions using an exception in/out parameter.
     """
index fe31c7d..54a0b01 100644 (file)
@@ -101,7 +101,7 @@ class MediaPlayer:
             if p:
                 o.set_media(i.media_new(p[0]))
             return o
-
+    
     def get_instance(self):
         """Return the associated vlc.Instance.
         """