+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/
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)
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))
#!/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))
-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
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)
del devloc, sys, os, dl
from _gst import *
-
-def threads_init():
- import gtk
- gtk.threads_init()
(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
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)
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)
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)
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,
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)
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,
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;
+
+}
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)
{
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");