gst/gstmodule.c (init_gst): Add constants for GST_*SECOND.
authorJohan Dahlin <johan@gnome.org>
Wed, 24 Mar 2004 10:31:35 +0000 (10:31 +0000)
committerJohan Dahlin <johan@gnome.org>
Wed, 24 Mar 2004 10:31:35 +0000 (10:31 +0000)
Original commit message from CVS:
* gst/gstmodule.c (init_gst): Add constants for GST_*SECOND.
(python_do_pending_calls): New idler handler, similar to pygtk, so
python events (eg KeyboardInterrupt) can be raised during mainloop

* gst/gst.override (_wrap_gst_bin_get_list):
(_wrap_gst_pad_tp_repr, caps_length, caps_item)
(structure_length, structure_subscript)
(_wrap_gst_structure_tp_repr): Impl.
(_wrap_gst_main): Override with threading blocking.

* gst/gst-types.defs (Object): add flags field.
(Structure): Add copy/release funcs

* gst/__init__.py (devloc): Don't initialize threads

* gst/Makefile.am: clean up

* examples/gst/player.py: Prettify and simplify. Uses GstThread now.

* examples/gstplay/player.py: Update to new api and make it work.

ChangeLog
examples/gst/player.py
examples/gstplay/player.py
gst/Makefile.am
gst/__init__.py
gst/gst-types.defs
gst/gst.override
gst/gstmodule.c

index 6d737e1..43f6c0f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2004-03-24  Johan Dahlin  <johan@gnome.org>
+
+       * gst/gstmodule.c (init_gst): Add constants for GST_*SECOND.
+       (python_do_pending_calls): New idler handler, similar to pygtk, so
+       python events (eg KeyboardInterrupt) can be raised during mainloop
+       
+       * gst/gst.override (_wrap_gst_bin_get_list): 
+       (_wrap_gst_pad_tp_repr, caps_length, caps_item) 
+       (structure_length, structure_subscript) 
+       (_wrap_gst_structure_tp_repr): Impl.
+       (_wrap_gst_main): Override with threading blocking.
+
+       * gst/gst-types.defs (Object): add flags field.
+       (Structure): Add copy/release funcs
+
+       * gst/__init__.py (devloc): Don't initialize threads
+
+       * gst/Makefile.am: clean up
+
+       * examples/gst/player.py: Prettify and simplify. Uses GstThread now.
+
+       * examples/gstplay/player.py: Update to new api and make it work.
+
 2004-03-18  Johan Dahlin  <johan@gnome.org>
 
        * configure.ac: s/GST_*_INCLUDES/GST_*_LIBS/
index eccbd24..d0bdc15 100755 (executable)
@@ -4,28 +4,23 @@ import sys
 
 import gst
 
-def found_tags(element, source, tags):
+def found_tags_cb(element, source, tags):
     for tag in tags.keys():
         print "%s: %s" % (gst.tag_get_nick(tag), tags[tag])
 
-#def error(source, error, debug):
-
-def deep_notify(*args):
-    pass
-
-def error(*args):
+def error_cb(*args):
     print args
 
 def playfile(filename):
-    bin = gst.Pipeline('player')
-    bin.connect('deep-notify', deep_notify)
-    bin.connect('error', error)
-    
+    bin = gst.Thread('player')
+    bin.connect('eos', lambda x: gst.main_quit())
+    bin.connect('error', error_cb)
+
     source = gst.Element('filesrc', 'src')
     source.set_property('location', filename)
 
     spider = gst.Element('spider', 'spider')
-    spider.connect('found-tag', found_tags)
+    spider.connect('found-tag', found_tags_cb)
     
     sink = gst.Element('osssink', 'sink')
     #sink.set_property('release-device', 1)
@@ -33,36 +28,20 @@ def playfile(filename):
     bin.add_many(source, spider, sink)
     if not gst.element_link_many(source, spider, sink):
         print "ERROR: could not link"
-        sys.exit (1)
+        return 2
 
     print 'Playing:', os.path.basename(filename)
     if not bin.set_state(gst.STATE_PLAYING):
         print "ERROR: could not set bin to playing"
-        sys.exit (1)
+        return 2
 
-    playing = 1
-    while playing:
-        try:
-             if not bin.iterate():
-                 playing = 0
-        except KeyboardInterrupt:
-            if not bin.set_state(gst.STATE_PAUSED):
-                print "ERROR: could not set bin to paused"
-                sys.exit (1)
-           print "Paused.  Press Enter to go back to playing."
-            try:
-                sys.stdin.readline ()
-                if not bin.set_state(gst.STATE_PLAYING):
-                    print "ERROR: could not set bin to playing"
-                    sys.exit (1)
-               print "Playing."
-            except KeyboardInterrupt:
-                playing = 0 
-    print "DONE playing"
-    bin.set_state(gst.STATE_NULL)
+    gst.main()
 
 def main(args):
-    map(playfile, args[1:])
+    if len(args) != 2:
+        print 'Usage; player.py filename'
+        return 1
+    return playfile(args[1])
 
 if __name__ == '__main__':
    sys.exit(main(sys.argv))
index af50662..d5a1175 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #
-# gst-python
 # Copyright (C) 2004 David I. Lehn
+#               2004 Johan Dahlin
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
 # License along with this library; if not, write to the
 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 # Boston, MA 02111-1307, USA.
-# 
-# Author: David I. Lehn <dlehn@users.sourceforge.net>
-#
-
-#
-# GstPlay wrapper demo
-#
 
 import sys
-import gobject
-from gstreamer import *
-from gstplay import Play
-
-try:
-    threads_init()
-except Exception, e:
-    print e
+import gst
+import gst.play
 
-def nano_time_string(nanos):
-    ts = nanos / 1000000000
-    h = ts / 3600
-    m = ts / 60
-    s = ts % 60
-    us = nanos % 1000000000
-    return '%02d:%02d:%02d.%06d' % (h, m, s, us)
+def nano2str(nanos):
+    ts = nanos / gst.SECOND
+    return '%02d:%02d:%02d.%06d' % (ts / 3600,
+                                    ts / 60,
+                                    ts % 60,
+                                    nanos % gst.SECOND)
 
-def got_time_tick(sender, nanos):
-    print 'time tick %s (%d)' % (nano_time_string(nanos), nanos)
+def stream_length_cb(play, ns):
+    print 'stream length: %s' % nano2str(ns)
 
-def got_stream_length(sender, nanos):
-    print 'stream length %s (%d)' % (nano_time_string(nanos), nanos)
-
-def got_have_video_size(sender, w, h):
+def have_video_size_cb(play, w, h):
     print 'video size %d %d' % (w, h)
 
-def got_found_tag(sender, src, tags, *args):
-    def fe(tl, tag):
-        c = tl.get_tag_size(tag)
-        #print tl, tag, c
-        for i in range(c):
-            v = tl.get_value_index(tag, i)
-            #print tag, type(v)
-            if i == 0:
-                s = gst_tag_get_nick(tag)
-            else:
-                s = ' '
-            print "%15s: %s" % (s, v)
-    print 'found tag', src, tags, args
-    tags.foreach(fe)
-
-def got_eos(sender, loop):
-    print 'eos', args
-    loop.quit()
-
-def idle_iterate(sender):
-    #threads_enter()
-    return sender.iterate()
-    #threads_leave()
-    #return sender.get_state() == STATE_PLAYING
+def found_tag_cb(play, src, tags):
+    for tag in tags.keys():
+        print "%s: %s" % (gst.tag_get_nick(tag), tags[tag])
 
-def main():
-    "Basic example to play a media stream with GstPlay"
-    #gst_debug_set_default_threshold(LEVEL_INFO)
-
-    if len(sys.argv) != 2:
-        print 'usage: %s <media file>' % (sys.argv[0])
+def main(args):
+    if len(args) != 2:
+        print 'Usage: %s file' % args[0]
         return -1
 
-    #threads_enter()
-
-    loop = gobject.MainLoop()
-
-    # the player
-    play = Play ()
-    play.connect('time_tick', got_time_tick)
-    play.connect('stream_length', got_stream_length)
-    play.connect('have_video_size', got_have_video_size)
-    play.connect('found_tag', got_found_tag)
-    play.connect('eos', got_eos, loop)
-
-    data_src = Element ('gnomevfssrc', 'data_src')
-    #audio_sink = Element ('osssink', 'audio_sink')
-    audio_sink = Element ('fakesink', 'audio_sink')
-    video_sink = Element ('fakesink', 'video_sink')
-    #video_sink = Element ('aasink', 'video_sink')
-    #video_sink.set_property('driver', 4)
-    #vis_sink = Element ('fakesink', 'vis_sink')
-
-    # setup the player
-    play.set_data_src(data_src)
-    play.set_audio_sink(audio_sink)
-    play.set_video_sink(video_sink)
-    #play.set_visualization(vis_sink)
-    play.set_location(sys.argv[1])
-
-    # start playing
-    play.set_state(STATE_PLAYING);
-
-    #while play.iterate(): pass
-    #while play.iterate(): print '.'
-    gobject.idle_add(idle_iterate, play)
-    #iterid = add_iterate_bin(play)
-
-    #import gtk
-    #gtk.threads_enter()
-    loop.run()
-    #gtk.threads_leave()
-
-    #threads_leave()
-
-    # stop the bin
-    play.set_state(STATE_NULL)
-
-    return 0
-
+    filename = args[1]
+    
+    play = gst.play.Play()
+    play.connect('stream-length', stream_length_cb)
+    play.connect('have-video-size', have_video_size_cb)
+    play.connect('found-tag', found_tag_cb)
+    play.connect('eos', lambda p: gst.main_quit())
+
+    # Setup source and sinks
+    play.set_data_src(gst.Element('filesrc'))
+    play.set_audio_sink(gst.Element('osssink'))
+    play.set_video_sink(gst.Element('fakesink'))
+
+    # Point location to our filename
+    play.set_location(filename)
+
+    # Start playing the stream
+    play.set_state(gst.STATE_PLAYING)
+    gst.main()
+    
 if __name__ == '__main__':
-    ret = main()
-    sys.exit(ret)
+    sys.exit(main(sys.argv))
index ebe892a..b852d0b 100644 (file)
@@ -1,26 +1,16 @@
-INCLUDES = $(PYTHON_INCLUDES) $(PYGTK_CFLAGS)
-PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
-
-defs_DATA = 
-defsdir = $(pkgdatadir)/2.0/defs
-
-EXTRA_DIST = $(defs_DATA) arg-types.py
+common_cflags = $(GST_CFLAGS) -fno-strict-aliasing
+common_libadd = $(GST_LIBS)
+common_ldflags = -module -avoid-version
 
 pkgpythondir = $(pythondir)/gst
 pkgpyexecdir = $(pyexecdir)/gst
 
-common_ldflags = -module -avoid-version
-
 pygstdir = $(pkgpythondir)
 pygst_PYTHON = __init__.py
 
 pygstexecdir = $(pkgpyexecdir)
+pygstexec_LTLIBRARIES = _gst.la $(interface_lib) $(play_lib)
 
-# GStreamer bindings
-GST_OVERRIDES = gst.override gstpad-handlers.override
-GST_DEFS = gst.defs gst-types.defs
-
-# what shall we build ?
 if BUILD_INTERFACES
 interface_lib = interfaces.la
 else
@@ -32,42 +22,47 @@ else
 play_lib =
 endif
 
-pygstexec_LTLIBRARIES = _gst.la $(interface_lib) $(play_lib)
+defs_DATA = 
+defsdir = $(pkgdatadir)/2.0/defs
 
-# how shall we build them ?
-_gst_la_CFLAGS = $(GST_CFLAGS) -fno-strict-aliasing
-_gst_la_LIBADD = $(GST_LIBS)
+INCLUDES = $(PYTHON_INCLUDES) $(PYGTK_CFLAGS)
+EXTRA_DIST = $(defs_DATA) arg-types.py
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+
+# GStreamer bindings
+_gst_la_CFLAGS = $(common_cflags)
+_gst_la_LIBADD = $(common_libadd)
 _gst_la_LDFLAGS = $(common_ldflags) -export-symbols-regex init_gst
 _gst_la_SOURCES = gst-argtypes.c gstmodule.c 
 nodist__gst_la_SOURCES = gst.c
+GST_OVERRIDES = gst.override gstpad-handlers.override
+GST_DEFS = gst.defs gst-types.defs
 CLEANFILES = gst.c
 EXTRA_DIST += $(GST_OVERRIDES)
 defs_DATA += $(GST_DEFS)
 gst.c: $(GST_DEFS) $(GST_OVERRIDES)
 
 # gst-play bindings
-PLAY_OVERRIDES = play.override
-PLAY_DEFS = play.defs
-
-play_la_CFLAGS = $(GST_CFLAGS) $(GST_PLAY_CFLAGS) -fno-strict-aliasing
-play_la_LIBADD = $(GST_LIBS) $(GST_PLAY_LIBS)
+play_la_CFLAGS = $(common_cflags) $(GST_PLAY_CFLAGS) 
+play_la_LIBADD = $(common_libadd) $(GST_PLAY_LIBS)
 play_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initplay
 play_la_SOURCES = playmodule.c
 nodist_play_la_SOURCES = play.c
+PLAY_OVERRIDES = play.override
+PLAY_DEFS = play.defs
 CLEANFILES += play.c
 EXTRA_DIST += $(PLAY_OVERRIDES)
 defs_DATA += $(PLAY_DEFS)
 play.c: $(PLAY_DEFS) $(PLAY_OVERRIDES)
 
 # GStreamer interfaces bindings
-INTERFACES_OVERRIDES = interfaces.override xoverlay.override
-INTERFACES_DEFS = interfaces.defs xoverlay.defs xwindowlistener.defs
-
-interfaces_la_CFLAGS = $(GST_CFLAGS) $(GST_INTERFACES_CFLAGS) -fno-strict-aliasing
-interfaces_la_LIBADD = $(GST_LIBS) $(GST_INTERFACES_LIBS)
+interfaces_la_CFLAGS = $(common_cflags) $(GST_INTERFACES_CFLAGS) 
+interfaces_la_LIBADD = $(common_libadd) $(GST_INTERFACES_LIBS)
 interfaces_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initinterface
 interfaces_la_SOURCES = interfacesmodule.c
 nodist_interfaces_la_SOURCES = interfaces.c
+INTERFACES_OVERRIDES = interfaces.override xoverlay.override
+INTERFACES_DEFS = interfaces.defs xoverlay.defs xwindowlistener.defs
 CLEANFILES += interfaces.c
 EXTRA_DIST += $(INTERFACES_OVERRIDES)
 defs_DATA += $(INTERFACES_DEFS)
index c466e28..8828eae 100644 (file)
@@ -36,7 +36,3 @@ sys.setdlopenflags(dl.RTLD_LAZY | dl.RTLD_GLOBAL)
 del devloc, sys, os, dl
 
 from _gst import *
-
-def threads_init():
-    import gtk
-    gtk.threads_init()
index f2b49ae..2d43c71 100644 (file)
@@ -6,6 +6,9 @@
   (parent "GObject")
   (c-name "GstObject")
   (gtype-id "GST_TYPE_OBJECT")
+  (fields 
+     '("guint32" "flags")
+  )
 )
 
 (define-object Index
 )
 
 
-;;
-;; 0.7 Boxed types
-;;
-
 (define-boxed Structure
   (in-module "Gst")
   (c-name "GstStructure")
   (gtype-id "GST_TYPE_STRUCTURE")
+  (copy-func "gst_structure_copy")
+  (release-func "gst_structure_unref")
 )
 
 (define-boxed TagList
index 2c78ae9..ea769d1 100644 (file)
@@ -153,6 +153,26 @@ _wrap_gst_bin_iterate(PyGObject *self)
        return PyInt_FromLong(ret);
 }
 %%
+override gst_bin_get_list
+static PyObject *
+_wrap_gst_bin_get_list(PyGObject *self)
+{
+       GList *elements, *l;
+       PyObject *tuple;
+       int i;
+       
+       elements = (GList*)gst_bin_get_list(GST_BIN(self->obj));
+       tuple = PyTuple_New(g_list_length(elements));
+       for (i = 0, l = elements; l; l = l->next, i++) {
+               GstElement *element = (GstElement*)l->data;
+               if (!element)
+                       continue;
+               PyTuple_SetItem(tuple, i, pygobject_new(G_OBJECT(element)));
+       }
+               
+       return tuple;
+}
+%%
 override gst_element_get_pad_list noargs
 static PyObject *
 _wrap_gst_element_get_pad_list(PyGObject *self)
@@ -190,6 +210,22 @@ _wrap_gst_element_set_state(PyGObject *self, PyObject *args, PyObject *kwargs)
        return PyInt_FromLong(ret);
 }
 %%
+override-slot GstPad.tp_repr
+static PyObject *
+_wrap_gst_pad_tp_repr (PyGObject *self)
+{
+       char *buf;
+       PyObject *retval;
+       
+       buf = g_strdup_printf("<GstPad (%s) at %lx>",
+                             gst_pad_get_name(GST_PAD(self->obj)),
+                             (long)self->obj);
+
+       retval = PyString_FromString(buf);
+       g_free(buf);
+       return retval;
+}
+%%
 override gst_pad_query kwargs
 static PyObject *
 _wrap_gst_pad_query(PyGObject *self, PyObject *args, PyObject *kwargs)
@@ -439,6 +475,39 @@ _wrap_gst_pad_get_negotiated_caps(PyGObject *self)
        return pyg_boxed_new(GST_TYPE_CAPS, ret, TRUE, TRUE);
 }
 %%
+override-slot GstCaps.tp_as_sequence
+static int
+caps_length(PyGObject *self)
+{
+       return gst_caps_get_size((GstCaps*)self->obj);
+}
+
+static PyObject *
+caps_item(PyGObject *self, int i)
+                       
+{
+       GstStructure *structure;
+       
+       if (i < 0 || i >= gst_caps_get_size((GstCaps*)self->obj)) {
+               PyErr_SetString(PyExc_IndexError, "list index out of range");
+               return NULL;
+       }
+       
+       structure = gst_caps_get_structure((GstCaps*)self->obj, i);
+       return pyg_boxed_new(GST_TYPE_STRUCTURE, structure, TRUE, TRUE);
+}
+
+static PySequenceMethods _wrap_gst_caps_tp_as_sequence = {
+       (inquiry)caps_length,         /* mp_length */
+        NULL,
+        NULL,
+       (intargfunc)caps_item,
+        NULL,
+       NULL,
+       NULL,
+        NULL,
+};
+%%
 override gst_buffer_new kwargs
 static int
 _wrap_gst_buffer_new(PyGBoxed *self, PyObject *args, PyObject *kwargs)
@@ -677,6 +746,40 @@ _wrap_gst_structure_set_value(PyObject *self, PyObject *args, PyObject *kwargs)
        return Py_None;
 }
 %%
+override-slot GstStructure.tp_as_mapping
+static int
+_wrap_gst_structure_length(PyGObject *self)
+{
+       return gst_structure_n_fields((GstStructure*)self->obj);
+}
+
+static PyObject *
+_wrap_gst_structure_subscript(PyGObject *self, PyObject *py_key)
+{
+       PyObject *v = NULL;
+       const char *field = PyString_AsString(py_key);
+       
+       if (gst_structure_has_field((GstStructure*)self->obj, field)) {
+               const GValue *gvalue;
+               gvalue = gst_structure_get_value((GstStructure*)self->obj, field);
+               g_assert(gvalue != NULL);
+               v = pyg_value_as_pyobject(gvalue, TRUE);
+       } else {
+               PyErr_SetString(PyExc_KeyError, field);
+       }
+               
+       if (v != NULL)
+               Py_INCREF(v);
+       return v;
+}
+
+static PySequenceMethods _wrap_gst_structure_tp_as_mapping = {
+       (inquiry)_wrap_gst_structure_length,         /* mp_length */
+       (binaryfunc)_wrap_gst_structure_subscript,   /* mp_subscript */
+       NULL,
+};
+
+%%
 override gst_structure_foreach kwargs
 static gboolean
 pygst_structure_foreach_marshal(GQuark field_id,
@@ -691,9 +794,6 @@ pygst_structure_foreach_marshal(GQuark field_id,
 
        pyg_block_threads();
 
-       //py_model = pygobject_new((GObject *)model);
-       //py_path = pygtk_tree_path_to_pyobject(path);
-       //py_iter = pyg_boxed_new(GTK_TYPE_TREE_ITER, iter, TRUE, TRUE);
        py_field = Py_BuildValue("s", g_quark_to_string(field_id));
        py_value = pyg_value_as_pyobject(value, FALSE);
        if (cunote->data)
@@ -749,8 +849,23 @@ _wrap_gst_structure_foreach (PyGObject *self,
        return Py_None;
 }
 %%
-override gst_tag_list_foreach kwargs
+override-slot GstStructure.tp_repr
+static PyObject *
+_wrap_gst_structure_tp_repr (PyGObject *self)
+{
+       char *buf;
+       PyObject *retval;
+       
+       buf = g_strdup_printf("<GstStructure (%s) at %lx>",
+                             gst_structure_get_name((GstStructure*)self->obj),
+                             (long)self->obj);
 
+       retval = PyString_FromString(buf);
+       g_free(buf);
+       return retval;
+}
+%%
+override gst_tag_list_foreach kwargs
 static gboolean
 pygst_tag_list_foreach_marshal(GstTagList *list,
                               const gchar *tag,
@@ -912,3 +1027,19 @@ _wrap_gst_g_error_tp_str(PyGObject *self)
     return PyString_FromString(gst_error_get_message (error->domain,
                                                      error->code));
 }
+%%
+override gst_main noargs
+static PyObject *
+_wrap_gst_main(PyObject *self)
+{
+       pyg_unblock_threads();
+       gst_main();
+       pyg_block_threads();
+       
+       if (PyErr_Occurred())
+               return NULL;
+       
+        Py_INCREF(Py_None);
+        return Py_None;
+
+}
index 049b03d..0863ba1 100644 (file)
@@ -34,6 +34,24 @@ void pygst_add_constants(PyObject *module, const gchar *strip_prefix);
                
 extern PyMethodDef pygst_functions[];
 
+static gboolean
+python_do_pending_calls(gpointer data)
+{
+    gboolean quit = FALSE;
+      
+    pyg_block_threads();
+    if (PyErr_CheckSignals() == -1) {
+       PyErr_SetNone(PyExc_KeyboardInterrupt);
+       quit = TRUE;
+    }
+    pyg_unblock_threads();
+
+    if (quit)
+       gst_main_quit();
+    
+    return TRUE;
+}
+
 DL_EXPORT(void)
 init_gst (void)
 {
@@ -85,9 +103,15 @@ init_gst (void)
                            PYGST_MICRO_VERSION);
      PyDict_SetItemString(d, "pygst_version", tuple);
      Py_DECREF(tuple);
+
+     PyModule_AddIntConstant(m, "SECOND", GST_SECOND);
+     PyModule_AddIntConstant(m, "MSECOND", GST_MSECOND);
+     PyModule_AddIntConstant(m, "NSECOND", GST_NSECOND);
      
      pygst_register_classes (d);
      pygst_add_constants (m, "GST_");
+
+     g_timeout_add_full (0, 100, python_do_pending_calls, NULL, NULL);
      
      if (PyErr_Occurred ()) {
          Py_FatalError ("can't initialize module gst");