1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
#
# gst-python - Python bindings for GStreamer
# Copyright (C) 2002 David I. Lehn
# Copyright (C) 2004 Johan Dahlin
# Copyright (C) 2005 Edward Hervey
# Copyright (C) 2005 Thomas Vander Stichele
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from common import gobject, gst, unittest, TestCase, pygobject_2_13
import sys
import time
# see
# http://www.sicem.biz/personal/lgs/docs/gobject-python/gobject-tutorial.html
class MyBin(gst.Bin):
_state_changed = False
def __init__(self, name):
# we need to call GObject's init to be able to do self.do_*
gobject.GObject.__init__(self)
# since we can't chain up to our parent's __init__, we set the
# name manually
self.set_property('name', name)
def do_change_state(self, state_change):
if state_change == gst.STATE_CHANGE_PAUSED_TO_PLAYING:
self._state_changed = True
# FIXME: it seems a vmethod increases the refcount without unreffing
# print self.__gstrefcount__
# print self.__grefcount__
# chain up to parent
return gst.Bin.do_change_state(self, state_change)
# we need to register the type for PyGTK < 2.8
gobject.type_register(MyBin)
# FIXME: fix leak in vmethods before removing overriding fixture
class BinSubclassTest(TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def testStateChange(self):
bin = MyBin("mybin")
self.assertEquals(bin.__gstrefcount__, 1)
self.assertEquals(sys.getrefcount(bin), pygobject_2_13 and 2 or 3)
self.assertEquals(bin.get_name(), "mybin")
self.assertEquals(bin.__gstrefcount__, 1)
# test get_state with no timeout
(ret, state, pending) = bin.get_state()
self.failIfEqual(ret, gst.STATE_CHANGE_FAILURE)
self.assertEquals(bin.__gstrefcount__, 1)
# set to playing
bin.set_state(gst.STATE_PLAYING)
self.failUnless(bin._state_changed)
# test get_state with no timeout
(ret, state, pending) = bin.get_state()
self.failIfEqual(ret, gst.STATE_CHANGE_FAILURE)
if ret == gst.STATE_CHANGE_SUCCESS:
self.assertEquals(state, gst.STATE_PLAYING)
self.assertEquals(pending, gst.STATE_VOID_PENDING)
# test get_state with a timeout
(ret, state, pending) = bin.get_state(1)
self.failIfEqual(ret, gst.STATE_CHANGE_FAILURE)
if ret == gst.STATE_CHANGE_SUCCESS:
self.assertEquals(state, gst.STATE_PLAYING)
self.assertEquals(pending, gst.STATE_VOID_PENDING)
(ret, state, pending) = bin.get_state(timeout=gst.SECOND)
# back to NULL
bin.set_state(gst.STATE_NULL)
class BinAddRemove(TestCase):
def setUp(self):
TestCase.setUp(self)
self.bin = gst.Bin('bin')
def tearDown(self):
del self.bin
TestCase.tearDown(self)
def testError(self):
gst.info("creating fakesrc")
src = gst.element_factory_make('fakesrc', 'name')
gst.info("creating fakesink")
sink = gst.element_factory_make('fakesink', 'name')
gst.info("adding src:%d to bin" % src.__gstrefcount__)
self.assertEqual(src.__gstrefcount__, 1)
self.bin.add(src)
self.assertEqual(src.__gstrefcount__, 2)
gst.info("added src:%d" % src.__gstrefcount__)
self.assertRaises(gst.AddError, self.bin.add, sink)
self.assertRaises(gst.AddError, self.bin.add, src)
self.assertRaises(gst.RemoveError, self.bin.remove, sink)
gst.info("removing src")
self.bin.remove(src)
gst.info("removed")
self.assertRaises(gst.RemoveError, self.bin.remove, src)
def testMany(self):
src = gst.element_factory_make('fakesrc')
sink = gst.element_factory_make('fakesink')
self.bin.add(src, sink)
self.assertRaises(gst.AddError, self.bin.add, src, sink)
self.bin.remove(src, sink)
self.assertRaises(gst.RemoveError, self.bin.remove, src, sink)
class Preroll(TestCase):
def setUp(self):
TestCase.setUp(self)
self.bin = gst.Bin('bin')
def tearDown(self):
# FIXME: wait for state change thread to settle down
while self.bin.__gstrefcount__ > 1:
time.sleep(0.1)
self.assertEquals(self.bin.__gstrefcount__, 1)
del self.bin
TestCase.tearDown(self)
def testFake(self):
src = gst.element_factory_make('fakesrc')
sink = gst.element_factory_make('fakesink')
self.bin.add(src)
# bin will go to paused, src pad task will start and error out
self.bin.set_state(gst.STATE_PAUSED)
ret = self.bin.get_state()
self.assertEquals(ret[0], gst.STATE_CHANGE_SUCCESS)
self.assertEquals(ret[1], gst.STATE_PAUSED)
self.assertEquals(ret[2], gst.STATE_VOID_PENDING)
# adding the sink will cause the bin to go in preroll mode
gst.debug('adding sink and setting to PAUSED, should cause preroll')
self.bin.add(sink)
sink.set_state(gst.STATE_PAUSED)
ret = self.bin.get_state(timeout=0)
self.assertEquals(ret[0], gst.STATE_CHANGE_ASYNC)
self.assertEquals(ret[1], gst.STATE_PAUSED)
self.assertEquals(ret[2], gst.STATE_PAUSED)
# to actually complete preroll, we need to link and re-enable fakesrc
src.set_state(gst.STATE_READY)
src.link(sink)
src.set_state(gst.STATE_PAUSED)
ret = self.bin.get_state()
self.assertEquals(ret[0], gst.STATE_CHANGE_SUCCESS)
self.assertEquals(ret[1], gst.STATE_PAUSED)
self.assertEquals(ret[2], gst.STATE_VOID_PENDING)
self.bin.set_state(gst.STATE_NULL)
self.bin.get_state()
class ConstructorTest(TestCase):
def testGood(self):
bin = gst.Bin()
bin = gst.Bin(None)
bin = gst.Bin('')
bin = gst.Bin('myname')
def testBad(self):
# these are now valid. pygobject will take care of converting
# the arguments to a string.
#self.assertRaises(TypeError, gst.Bin, 0)
#self.assertRaises(TypeError, gst.Bin, gst.Bin())
pass
if __name__ == "__main__":
unittest.main()
|