summaryrefslogtreecommitdiff
path: root/testsuite/test_bin.py
blob: 2d04807a4c5b0b6dca579e37e1ba368d8fd64989 (plain)
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 02111-1307  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()