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
|
"""Video widget for displaying a gstreamer pipe
Note: currently this module is not all that elegant or useful,
we need a better recipe for using and working with Video
under OLPCGames.
"""
import logging
log = logging.getLogger( 'olpcgames.video' )
#log.setLevel( logging.INFO )
import os
import signal
import pygame
import weakref
import olpcgames
from olpcgames import _gtkmain
import pygtk
pygtk.require('2.0')
import gtk
import gst
class VideoWidget(gtk.DrawingArea):
"""Widget to render GStreamer video over our Pygame Canvas
The VideoWidget is a simple GTK window which is
held by the PygameCanvas, just as is the Pygame
window we normally use. As such this approach
*cannot* work without the GTK wrapper.
It *should* be possible to use raw X11 operations
to create a child window of the Pygame/SDL window
and use that for the same purpose, but that would
require some pretty low-level ctypes hacking.
Attributes of Note:
rect -- Pygame rectangle which tells us where to
display ourselves, setting the rect changes the
position and size of the window.
"""
_imagesink = None
_renderedRect = None
def __init__(self, rect=None, force_aspect_ratio=True):
super(VideoWidget, self).__init__()
self.unset_flags(gtk.DOUBLE_BUFFERED)
if rect is None:
rect = pygame.Rect( (0,0), (160,120))
self.rect = rect
self.force_aspect_ratio = force_aspect_ratio
self.set_size_request(rect.width,rect.height)
olpcgames.WIDGET.put( self, rect.left,rect.top)
self._renderedRect = rect
self.show()
def set_rect( self, rect ):
"""Set our rectangle (area of the screen)"""
log.debug( 'Set rectangle: %s', rect )
self.set_size_request(rect.width,rect.height)
olpcgames.WIDGET.move( self, rect.left,rect.top)
self.rect = rect
def do_expose_event(self, event):
"""Handle exposure event (trigger redraw by gst)"""
if self._imagesink:
self._imagesink.expose()
return False
else:
return True
def set_sink(self, sink):
"""Set our window-sink for output"""
assert self.window.xid
self._imagesink = sink
self._imagesink.set_xwindow_id(self.window.xid)
self._imagesink.set_property('force-aspect-ratio', self.force_aspect_ratio)
class PygameWidget( object ):
"""Render "full-screen" video to the entire Pygame screen
Not particularly useful unless this happens to be exactly what you need.
"""
def __init__( self ):
try:
window_id = pygame.display.get_wm_info()['window']
except KeyError, err: # pygame-ctypes...
window_id = int(os.environ['SDL_WINDOWID'])
self.window_id = window_id
self._imagesink = None
#self._holder = _gtkmain.Holder()
def set_sink( self, sink ):
"""Set up our gst sink"""
log.info( 'Setting sink: %s', sink )
self._imagesink = sink
sink.set_xwindow_id( self.window_id )
#pipe_desc = 'v4l2src ! video/x-raw-yuv,width=160,height=120 ! ffmpegcolorspace ! xvimagesink'
class Player(object):
pipe_desc = 'v4l2src ! ffmpegcolorspace ! video/x-raw-yuv ! xvimagesink'
test_pipe_desc = 'videotestsrc ! ffmpegcolorspace ! video/x-raw-yuv ! xvimagesink'
_synchronized = False
def __init__(self, videowidget, pipe_desc=pipe_desc):
self._playing = False
self._videowidget = videowidget
self._pipeline = gst.parse_launch(pipe_desc)
bus = self._pipeline.get_bus()
bus.enable_sync_message_emission()
bus.add_signal_watch()
bus.connect('sync-message::element', self.on_sync_message)
bus.connect('message', self.on_message)
def play(self):
log.info( 'Play' )
if self._playing == False:
self._pipeline.set_state(gst.STATE_PLAYING)
self._playing = True
def pause(self):
log.info( 'Pause' )
if self._playing == True:
if self._synchronized:
log.debug( ' pause already sync\'d' )
self._pipeline.set_state(gst.STATE_PAUSED)
self._playing = False
def stop( self ):
"""Stop all playback"""
self._pipeline.set_state( gst.STATE_NULL )
def on_sync_message(self, bus, message):
log.info( 'Sync: %s', message )
if message.structure is None:
return
if message.structure.get_name() == 'prepare-xwindow-id':
self._synchronized = True
self._videowidget.set_sink(message.src)
def on_message(self, bus, message):
log.info( 'Message: %s', message )
t = message.type
if t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
log.warn("Video error: (%s) %s" ,err, debug)
self._playing = False
if __name__ == "__main__":
# Simple testing code...
logging.basicConfig()
log.setLevel( logging.DEBUG )
from pygame import image,display, event
import pygame
def main():
display.init()
maxX,maxY = display.list_modes()[0]
screen = display.set_mode( (maxX/3, maxY/3 ) )
display.flip()
pgw = PygameWidget( )
p = Player( pgw, pipe_desc=Player.test_pipe_desc )
p.play()
clock = pygame.time.Clock()
running = True
while running:
clock.tick( 60 )
for evt in [pygame.event.wait()] + pygame.event.get():
if evt.type == pygame.KEYDOWN:
if p._playing:
p.pause()
else:
p.play()
elif evt.type == pygame.QUIT:
p.stop()
running = False
#display.flip()
main()
|