1
# PiTiVi , Non-linear video editor
3
# tests/test_alpha_passthrough.py
5
# Copyright (c) 2010, Robert Swain <robert.swain@collabora.co.uk>
6
# Copyright (c) 2010, Alessandro Decina <alessandro.decina@collabora.co.uk>
8
# This program is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU Lesser General Public
10
# License as published by the Free Software Foundation; either
11
# version 2.1 of the License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
# Lesser General Public License for more details.
18
# You should have received a copy of the GNU Lesser General Public
19
# License along with this program; if not, write to the
20
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21
# Boston, MA 02110-1301, USA.
23
from unittest import TestCase
27
from pitivi.factories.test import VideoTestSourceFactory
28
from pitivi.stream import VideoStream
29
from pitivi.timeline.track import Track, SourceTrackObject
32
def set_one_keyframe(track_object, value):
33
interpolator = track_object.getInterpolator("alpha")
34
kf = list(interpolator.getKeyframes())[0]
35
interpolator.setKeyframeValue(kf, value)
38
def set_all_keyframes(track_object, value):
39
interpolator = track_object.getInterpolator("alpha")
40
if interpolator is not None:
41
for kf in interpolator.getKeyframes():
46
interpolator.setKeyframeValue(kf, val)
50
caps = gst.Caps("video/x-raw-yuv,format=(fourcc)%s" % fourcc)
51
return VideoStream(caps)
55
caps = gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,"
56
"endianness=(int)4321,red_mask=(int)16711680,"
57
"green_mask=(int)65280,blue_mask=(int)255")
58
return VideoStream(caps)
61
def make_track_object(stream):
62
factory = VideoTestSourceFactory()
63
factory.duration = 15 * gst.SECOND
64
return SourceTrackObject(factory, stream)
67
class TestAlpha(TestCase):
70
self.pipeline = gst.Pipeline()
72
self.track1 = Track(yuv("I420"))
73
track_object1 = make_track_object(yuv("I420"))
74
track_object2 = make_track_object(yuv("Y42B"))
75
track_object3 = make_track_object(yuv("Y444"))
76
track_object4 = make_track_object(rgb())
77
track_object5 = make_track_object(yuv("AYUV"))
79
for i, track_object in enumerate((track_object1, track_object2,
80
track_object3, track_object4, track_object5)):
81
self.track1.addTrackObject(track_object)
83
# set priorities from 1 to 5
84
track_object.priority = i + 1
86
# track_object5 falls outside (0s, 15s) so it isn't linked to videomixer
87
track_object5.start = 15 * gst.SECOND
89
# make a fakesink for the pipeline and connect it as necessary with a callback
90
composition = self.track1.composition
91
fakesink = gst.element_factory_make('fakesink')
93
def bin_pad_added_cb(composition, pad):
94
pad.link(fakesink.get_pad('sink'))
96
composition.connect("pad-added", bin_pad_added_cb)
98
# add the composition and fakesink to the pipeline and set state to paused to preroll
99
self.pipeline.add(composition)
100
self.pipeline.add(fakesink)
101
self.pipeline.set_state(gst.STATE_PAUSED)
103
# wait for preroll to complete
104
bus = self.pipeline.get_bus()
105
msg = bus.timed_pop_filtered(gst.CLOCK_TIME_NONE,
106
gst.MESSAGE_ASYNC_DONE | gst.MESSAGE_ERROR)
107
if msg.type == gst.MESSAGE_ERROR:
108
gerror, debug = msg.parse_error()
109
print "\nError message: %s\nDebug info: %s" % (gerror, debug)
110
self.failUnlessEqual(msg.type, gst.MESSAGE_ASYNC_DONE)
112
self.svmbin = list(self.track1.mixer.elements())[0]
115
self.pipeline.set_state(gst.STATE_NULL)
116
TestCase.tearDown(self)
118
def failUnlessAlphaIsSet(self):
119
# check that each SmartVideomixerBin input has alpha set on its
121
for input in self.svmbin.inputs.values():
122
capsfilter = input[2]
123
self.failUnless(capsfilter.props.caps[0].has_field("format"))
125
def failUnlessAlphaIsNotSet(self):
126
# check that each SmartVideomixerBin input has alpha _not_ set on its
128
for input in self.svmbin.inputs.values():
129
capsfilter = input[2]
130
self.failIf(capsfilter.props.caps[0].has_field("format"))
132
def testKeyframesOnDifferentObjects(self):
133
# no alpha < 1.0 keyframes
134
for track_obj in self.track1.track_objects:
135
set_all_keyframes(track_obj, 1.0)
136
self.failUnlessAlphaIsNotSet()
138
track_object1 = self.track1.track_objects[0]
139
track_object2 = self.track1.track_objects[1]
141
# one alpha < 1.0 keyframe
142
set_one_keyframe(track_object1, 0.8)
143
self.failUnlessAlphaIsSet()
145
# two alpha < 1.0 keyframes
146
set_one_keyframe(track_object2, 0.5)
147
self.failUnlessAlphaIsSet()
149
# one alpha < 1.0 keyframe
150
set_one_keyframe(track_object1, 1.0)
151
self.failUnlessAlphaIsSet()
153
# no alpha < 1.0 keyframes
154
set_one_keyframe(track_object2, 1.0)
156
self.failUnlessAlphaIsNotSet()
158
def testKeyframesOnSameObject(self):
159
for track_obj in self.track1.track_objects:
160
set_all_keyframes(track_obj, 1.0)
161
self.failUnlessAlphaIsNotSet()
163
track_object1 = self.track1.track_objects[0]
164
interpolator1 = track_object1.getInterpolator("alpha")
166
keyframe1 = interpolator1.newKeyframe(1 * gst.SECOND, 0.8)
167
self.failUnlessAlphaIsSet()
169
keyframe2 = interpolator1.newKeyframe(2 * gst.SECOND, 0.5)
170
self.failUnlessAlphaIsSet()
172
interpolator1.setKeyframeValue(keyframe1, 1.0)
173
self.failUnlessAlphaIsSet()
175
interpolator1.removeKeyframe(keyframe2)
176
self.failUnlessAlphaIsNotSet()
178
def testRemoveTrackObjects(self):
179
for track_obj in self.track1.track_objects:
180
set_all_keyframes(track_obj, 1.0)
182
self.failUnlessAlphaIsNotSet()
184
track_object1 = self.track1.track_objects[0]
185
track_object2 = self.track1.track_objects[1]
187
# set one keyframe below 1.0
188
set_one_keyframe(track_object1, 0.8)
189
self.failUnlessAlphaIsSet()
191
# track_object2 has no alpha < 1.0 keyframes, removing it shouldn't
192
# trigger an alpha change
193
self.track1.removeTrackObject(track_object2)
194
self.failUnlessAlphaIsSet()
196
# track_object1 does have an alpha < 1.0 keyframe, removing it should
197
# trigger an alpha change
198
self.track1.removeTrackObject(track_object1)
200
self.failUnlessAlphaIsNotSet()
202
def testRequestPads(self):
203
# requesting a new pad should never trigger an alpha change
205
template = gst.PadTemplate("sink_%u", gst.PAD_SINK, gst.PAD_REQUEST,
206
gst.Caps("video/x-raw-yuv;video/x-raw-rgb"))
208
for track_obj in self.track1.track_objects:
209
set_all_keyframes(track_obj, 1.0)
211
# when unset, should remain unset
212
self.failUnlessAlphaIsNotSet()
213
test_pad1 = self.svmbin.do_request_new_pad(template)
214
self.failUnlessAlphaIsNotSet()
216
obj = self.track1.track_objects[0]
217
set_one_keyframe(obj, 0.8)
219
# when set, should remain set
220
self.failUnlessAlphaIsSet()
221
test_pad2 = self.svmbin.do_request_new_pad(template)
222
self.failUnlessAlphaIsSet()
224
def testTransitions(self):
225
for track_obj in self.track1.track_objects:
226
set_all_keyframes(track_obj, 1.0)
227
self.failUnlessAlphaIsNotSet()
229
track_object1 = self.track1.track_objects[0]
230
track_object2 = self.track1.track_objects[1]
232
track_object1.start = 0
233
track_object2.start = 10 * gst.SECOND
235
old_priority = track_object2.priority
236
track_object2.priority = track_object1.priority
237
self.track1.updateTransitions()
238
self.failUnlessAlphaIsSet()
240
track_object2.priority = old_priority
241
self.track1.updateTransitions()
242
self.failUnlessAlphaIsNotSet()