From 15f1eb48cf556a8283e748520804a79c0fd039ad Mon Sep 17 00:00:00 2001 From: Johan Dahlin Date: Wed, 24 Mar 2004 10:31:35 +0000 Subject: [PATCH] gst/gstmodule.c (init_gst): Add constants for GST_*SECOND. 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 | 23 +++++++ examples/gst/player.py | 49 +++++---------- examples/gstplay/player.py | 147 ++++++++++++--------------------------------- gst/Makefile.am | 51 +++++++--------- gst/__init__.py | 4 -- gst/gst-types.defs | 9 +-- gst/gst.override | 139 ++++++++++++++++++++++++++++++++++++++++-- gst/gstmodule.c | 24 ++++++++ 8 files changed, 263 insertions(+), 183 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d737e1..43f6c0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2004-03-24 Johan Dahlin + + * 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 * configure.ac: s/GST_*_INCLUDES/GST_*_LIBS/ diff --git a/examples/gst/player.py b/examples/gst/player.py index eccbd24..d0bdc15 100755 --- a/examples/gst/player.py +++ b/examples/gst/player.py @@ -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)) diff --git a/examples/gstplay/player.py b/examples/gstplay/player.py index af50662..d5a1175 100755 --- a/examples/gstplay/player.py +++ b/examples/gstplay/player.py @@ -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 @@ -17,121 +17,52 @@ # 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 -# - -# -# 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 ' % (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)) diff --git a/gst/Makefile.am b/gst/Makefile.am index ebe892a..b852d0b 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -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) diff --git a/gst/__init__.py b/gst/__init__.py index c466e28..8828eae 100644 --- a/gst/__init__.py +++ b/gst/__init__.py @@ -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() diff --git a/gst/gst-types.defs b/gst/gst-types.defs index f2b49ae..2d43c71 100644 --- a/gst/gst-types.defs +++ b/gst/gst-types.defs @@ -6,6 +6,9 @@ (parent "GObject") (c-name "GstObject") (gtype-id "GST_TYPE_OBJECT") + (fields + '("guint32" "flags") + ) ) (define-object Index @@ -195,14 +198,12 @@ ) -;; -;; 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 diff --git a/gst/gst.override b/gst/gst.override index 2c78ae9..ea769d1 100644 --- a/gst/gst.override +++ b/gst/gst.override @@ -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("", + 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("", + 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; + +} diff --git a/gst/gstmodule.c b/gst/gstmodule.c index 049b03d..0863ba1 100644 --- a/gst/gstmodule.c +++ b/gst/gstmodule.c @@ -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"); -- 2.7.4