hornetseye-xorg 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/x11window.hh ADDED
@@ -0,0 +1,79 @@
1
+
2
+ /* HornetsEye - Computer Vision with Ruby
3
+ Copyright (C) 2006, 2007, 2008 ,2009 Jan Wedekind
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
+ #ifndef HORNETSEYE_X11WINDOW_HH
18
+ #define HORNETSEYE_X11WINDOW_HH
19
+
20
+ #include <boost/shared_ptr.hpp>
21
+ #include <X11/Xlib.h>
22
+ #include <X11/Xutil.h>
23
+ #include "x11display.hh"
24
+ #include "x11painter.hh"
25
+ #include "error.hh"
26
+
27
+ /** Class for opening X11 windows.
28
+
29
+ @date Fri Apr 29 23:10:01 UTC 2005 */
30
+ class X11Window
31
+ {
32
+ friend class X11Display;
33
+ public:
34
+ X11Window( X11DisplayPtr display, X11PainterPtr painter,
35
+ int width, int height, Window parent = 0 );
36
+ virtual ~X11Window(void);
37
+ int width(void) const { return m_width; }
38
+ int height(void) const { return m_height; }
39
+ void show(void) throw (Error);
40
+ void close(void);
41
+ void setTitle( const char *_title );
42
+ XVisualInfo *visualInfo(void) { return m_visualInfo; }
43
+ X11DisplayPtr display(void) { return m_display; }
44
+ Window get(void) { return m_window; }
45
+ void resize( int width, int height ) throw (Error);
46
+ void repaint( bool x11Event = false ) throw (Error);
47
+ GC gc(void) { return m_gc; }
48
+ virtual void handleEvent( XEvent &event ) throw (Error);
49
+ virtual void paintEvent( bool x11Event ) throw (Error);
50
+ virtual void keyEvent( XKeyEvent &xkey ) throw (Error);
51
+ static VALUE cRubyClass;
52
+ static VALUE registerRubyClass( VALUE module );
53
+ static void deleteRubyObject( void *ptr );
54
+ static VALUE wrapNew( VALUE rbClass, VALUE rbDisplay, VALUE rbX11Output,
55
+ VALUE rbWidth, VALUE rbHeight );
56
+ static VALUE wrapSetTitle( VALUE rbSelf, VALUE rbTitle );
57
+ static VALUE wrapWidth( VALUE rbSelf );
58
+ static VALUE wrapHeight( VALUE rbSelf );
59
+ static VALUE wrapResize( VALUE rbSelf, VALUE rbWidth, VALUE rbHeight );
60
+ static VALUE wrapShow( VALUE rbSelf );
61
+ static VALUE wrapClose( VALUE rbSelf );
62
+ protected:
63
+ static Bool waitForNotify( Display *, XEvent *e, char *arg );
64
+ X11DisplayPtr m_display;
65
+ XVisualInfo *m_visualInfo;
66
+ Colormap m_colourMap;
67
+ Window m_window;
68
+ GC m_gc;
69
+ X11PainterPtr m_painter;
70
+ int m_width;
71
+ int m_height;
72
+ Atom wmProtocols;
73
+ Atom wmDeleteWindow;
74
+ };
75
+
76
+ typedef boost::shared_ptr< X11Window > X11WindowPtr;
77
+
78
+ #endif
79
+
@@ -0,0 +1,152 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009 Jan Wedekind
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ * Raster graphics library
18
+ *
19
+ * Copyright (c) 1997-2002 Alfredo K. Kojima
20
+ *
21
+ * This library is free software; you can redistribute it and/or
22
+ * modify it under the terms of the GNU Library General Public
23
+ * License as published by the Free Software Foundation; either
24
+ * version 2 of the License, or (at your option) any later version.
25
+ *
26
+ * This library is distributed in the hope that it will be useful,
27
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
28
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29
+ * Library General Public License for more details.
30
+ *
31
+ * You should have received a copy of the GNU Library General Public
32
+ * License along with this library; if not, write to the Free
33
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34
+ */
35
+ #include <boost/shared_array.hpp>
36
+ #include <errno.h>
37
+ #ifndef NDEBUG
38
+ #include <iostream>
39
+ #endif
40
+ #include "ximagepainter.hh"
41
+ #include "rubytools.hh"
42
+ #include "x11window.hh"
43
+ #include "x11output.hh"
44
+
45
+ using namespace boost;
46
+ using namespace std;
47
+
48
+ VALUE XImagePainter::cRubyClass = Qnil;
49
+
50
+ void XImagePainter::paint( bool ) throw (Error)
51
+ {
52
+ #ifndef NDEBUG
53
+ cerr << "XImagePainter::paint()" << endl;
54
+ #endif
55
+
56
+ assert( m_window != NULL );
57
+
58
+ if ( m_imageSource != NULL ) {
59
+
60
+ #ifndef NDEBUG
61
+ cerr << "Requesting image." << endl;
62
+ #endif
63
+ FramePtr frame = m_imageSource->frame();
64
+
65
+ if ( frame ) {
66
+ // Create scaled BGRA data.
67
+ int
68
+ newWidth = m_window->width(),
69
+ newHeight = m_window->height();
70
+ boost::shared_array< unsigned char > array
71
+ ( new unsigned char[ newWidth * newHeight * 4 ] );
72
+ const char *p = frame->data();
73
+ int
74
+ fw = frame->width(),
75
+ dx = ( frame->width() << 16 ) / newWidth,
76
+ dy = ( frame->height() << 16 ) / newHeight,
77
+ py = 0;
78
+ unsigned char *d = array.get();
79
+ for ( int y=0; y<newHeight; y++ ) {
80
+ int t = fw * ( py >> 16 );
81
+ const char *s = p + ( t << 1 ) + t;/* 3 * t */
82
+ int
83
+ ox = 0,
84
+ px = 0;
85
+ for ( int x=0; x<newWidth; x++ ) {
86
+ px += dx;
87
+ *d++ = s[2];
88
+ *d++ = s[1];
89
+ *d++ = s[0];
90
+ *d++ = '\000';
91
+ t = ( px - ox ) >> 16;
92
+ ox += t << 16;
93
+ s += ( t << 1 ) + t;// s += 3 * t
94
+ }
95
+ py += dy;
96
+ };
97
+
98
+ // Display the scaled BGRA data.
99
+ XImage *xImage = XCreateImage( m_display->get(), m_visualInfo.visual,
100
+ 24, ZPixmap, 0,
101
+ (char *)array.get(),
102
+ newWidth, newHeight,
103
+ 32, newWidth * 4 );
104
+ ERRORMACRO( xImage != NULL, Error, ,
105
+ "Failed to create X11-image" );
106
+ xImage->byte_order = LSBFirst;
107
+ #ifndef NDEBUG
108
+ cerr << "Window size is " << newWidth << 'x'
109
+ << newHeight << endl;
110
+ #endif
111
+ XPutImage( m_display->get(), m_window->get(), m_window->gc(),
112
+ xImage, 0, 0, 0, 0, newWidth, newHeight );
113
+ xImage->data = (char *)NULL;
114
+ XDestroyImage( xImage );
115
+ };
116
+
117
+ };
118
+ }
119
+
120
+
121
+ XVisualInfo *XImagePainter::visualInfo( X11DisplayPtr display )
122
+ throw (Error)
123
+ {
124
+ ERRORMACRO( XMatchVisualInfo( display->get(),
125
+ DefaultScreen( display->get() ) != 0,
126
+ 24, TrueColor, &m_visualInfo), Error, ,
127
+ "Could not get 24-bit true-colour visual." );
128
+ m_display = display;
129
+ return &m_visualInfo;
130
+ }
131
+
132
+ VALUE XImagePainter::registerRubyClass( VALUE module,
133
+ VALUE cX11Output )
134
+ {
135
+ cRubyClass = rb_define_class_under( module, "XImageOutput", cX11Output );
136
+ rb_define_singleton_method( cRubyClass, "new",
137
+ RUBY_METHOD_FUNC( wrapNew ), 0 );
138
+ return cRubyClass;
139
+ }
140
+
141
+ VALUE XImagePainter::wrapNew( VALUE rbClass )
142
+ {
143
+ VALUE retVal = Qnil;
144
+ X11PainterPtr painter( new XImagePainter );
145
+ X11OutputPtr ptr( new X11Output( painter ) );
146
+ retVal = Data_Wrap_Struct( rbClass,
147
+ X11Output::markRubyObject,
148
+ X11Output::deleteRubyObject,
149
+ new X11OutputPtr( ptr ) );
150
+ return retVal;
151
+ }
152
+
@@ -0,0 +1,43 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009 Jan Wedekind
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ #ifndef HORNETSEYE_XIMAGEPAINTER_HH
17
+ #define HORNETSEYE_XIMAGEPAINTER_HH
18
+
19
+ #include <X11/X.h>
20
+ #include <boost/shared_ptr.hpp>
21
+ #include "x11painter.hh"
22
+ #include "x11display.hh"
23
+
24
+ class X11Window;
25
+
26
+ class XImagePainter: public X11Painter
27
+ {
28
+ public:
29
+ XImagePainter(void) {}
30
+ virtual void paint( bool x11Event ) throw (Error);
31
+ virtual XVisualInfo *visualInfo( X11DisplayPtr display ) throw (Error);
32
+ static VALUE cRubyClass;
33
+ static VALUE registerRubyClass( VALUE module, VALUE cX11Output );
34
+ static VALUE wrapNew( VALUE rbClass );
35
+ protected:
36
+ XVisualInfo m_visualInfo;
37
+ X11DisplayPtr m_display;
38
+ };
39
+
40
+ typedef boost::shared_ptr< XImagePainter > XImagePainterPtr;
41
+
42
+ #endif
43
+
@@ -0,0 +1,439 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007 Jan Wedekind
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ #ifndef NDEBUG
17
+ #include <iostream>
18
+ #include <iomanip>
19
+ #endif
20
+ #include <X11/Xlib.h>
21
+ #include <X11/Xutil.h>
22
+ #include "rubytools.hh"
23
+ #include "x11output.hh"
24
+ #include "x11window.hh"
25
+ #include "xvideoimagepainter.hh"
26
+
27
+ // also see xvwidget.cc
28
+
29
+ using namespace std;
30
+
31
+ VALUE XVideoImagePainter::cRubyClass = Qnil;
32
+ VALUE XVideoImagePainter::rbHornetseye = Qnil;
33
+
34
+ std::set< XvPortID > XVideoImagePainter::grabbedPorts;
35
+
36
+ XVideoImagePainter::XVideoImagePainter(void):
37
+ m_port(0), m_requireColourKey(false), m_colourKey(0), m_xvImage(NULL)
38
+ {
39
+ }
40
+
41
+ XVideoImagePainter::~XVideoImagePainter(void)
42
+ {
43
+ #ifndef NDEBUG
44
+ cerr << "Destroying XVideo image painter." << endl;
45
+ #endif
46
+ if ( m_xvImage != NULL ) {
47
+ XFree( m_xvImage );
48
+ };
49
+ }
50
+
51
+ void XVideoImagePainter::paint( bool x11Event ) throw (Error)
52
+ {
53
+ #ifndef NDEBUG
54
+ cerr << "XVideoImagePainter::paint( " << x11Event << " )" << endl;
55
+ #endif
56
+ assert( m_window != NULL );
57
+
58
+ // Draw colour key if X11 requires some redrawing
59
+ // (Colour key should not be drawn if the display merely has to
60
+ // show the next image).
61
+ if ( x11Event && m_requireColourKey ) {
62
+ XSetForeground( m_display->get(), m_window->gc(), m_colourKey );
63
+ XFillRectangle( m_display->get(), m_window->get(),
64
+ m_window->gc(), 0, 0,
65
+ m_window->width(), m_window->height() );
66
+ };
67
+
68
+ if ( m_imageSource != NULL ) {
69
+ #ifndef NDEBUG
70
+ cerr << "Requesting image." << endl;
71
+ #endif
72
+ FramePtr frame( m_imageSource->frame() );
73
+ if ( frame ) {
74
+ #ifndef NDEBUG
75
+ cerr << "XVideo-output for \"" << frame->typecode() << "\"." << endl;
76
+ #endif
77
+ int uid = selectFormat( typecodeToUID( frame->typecode() ) );
78
+ ERRORMACRO( uid != 0, Error, , "XVideo-extension does not "
79
+ "support YV12, I420, or RGB24" );
80
+ string typecode = uidToTypecode( uid );
81
+ if ( frame->typecode() != typecode ) {
82
+ VALUE
83
+ rbTypecode = rb_funcall( rbHornetseye, rb_intern( "const_get" ), 1,
84
+ rb_str_new( typecode.c_str(),
85
+ typecode.length() ) ),
86
+ rbFrame = rb_funcall( frame->rubyObject(), rb_intern( "to_type" ), 1,
87
+ rbTypecode );
88
+ frame = FramePtr( new Frame( rbFrame ) );
89
+ };
90
+ if ( m_xvImage != NULL ) {
91
+ if ( m_xvImage->id != uid ||
92
+ m_xvImage->width != frame->width() ||
93
+ m_xvImage->height != frame->height() ) {
94
+ XFree( m_xvImage );
95
+ m_xvImage = NULL;
96
+ };
97
+ };
98
+ if ( m_xvImage == NULL ) {
99
+ m_xvImage =
100
+ XvCreateImage( m_display->get(), m_port, uid,
101
+ (char *)frame->data(),
102
+ frame->width(), frame->height() );
103
+ #ifndef NDEBUG
104
+ cerr << "Created " << m_xvImage->width << 'x'
105
+ << m_xvImage->height << ' ' << frame->typecode()
106
+ << "-image for X video." << endl;
107
+ cerr << "# planes = " << m_xvImage->num_planes << endl;
108
+ for ( int i=0; i<m_xvImage->num_planes; i++ )
109
+ cerr << "offsets[" << i << "]=" << m_xvImage->offsets[i]
110
+ << endl
111
+ << "pitches[" << i << "]=" << m_xvImage->pitches[i]
112
+ << endl;
113
+ #endif
114
+ } else
115
+ m_xvImage->data = (char *)frame->data();
116
+
117
+ if ( frame->typecode() == "YV12" ) {
118
+ // YV12 requires alignment for X video output.
119
+ frame = alignYV12( frame );
120
+ m_xvImage->data = (char *)frame->data();
121
+ };
122
+ XvPutImage( m_display->get(), m_port, m_window->get(),
123
+ m_window->gc(), m_xvImage, 0, 0,
124
+ m_xvImage->width, m_xvImage->height, 0, 0,
125
+ m_window->width(), m_window->height() );
126
+ };
127
+ };
128
+ }
129
+
130
+ FramePtr XVideoImagePainter::alignYV12( FramePtr frame )
131
+ {
132
+ // YV12-images aligned by Xine sometimes do not fit the required
133
+ // output.
134
+ assert( m_xvImage != NULL );
135
+ int
136
+ width = frame->width(),
137
+ height = frame->height(),
138
+ width2 = ( width + 1 ) / 2,
139
+ height2 = ( height + 1 ) / 2,
140
+ widtha = ( width + 7 ) & ~0x7,
141
+ width2a = ( width2 + 7 ) & ~0x7;
142
+ assert( m_xvImage->offsets[0] == 0 );
143
+ FramePtr retVal;
144
+ if ( m_xvImage->offsets[1] != widtha * height ||
145
+ m_xvImage->offsets[2] != widtha * height + width2a * height2 ||
146
+ m_xvImage->pitches[0] != widtha ||
147
+ m_xvImage->pitches[1] != width2a ||
148
+ m_xvImage->pitches[2] != width2a ) {
149
+ #ifndef NDEBUG
150
+ cerr << "YV12-Image needs alignment." << endl;
151
+ #endif
152
+ FramePtr dest( new Frame( "YV12",
153
+ m_xvImage->width, m_xvImage->height ) );
154
+ const char
155
+ *src_y = frame->data();
156
+ const signed char
157
+ *src_v = (const signed char *)src_y + widtha * height,
158
+ *src_u = src_v + width2a * height2;
159
+ unsigned char
160
+ *dest_y = (unsigned char *)dest->data();
161
+ signed char
162
+ *dest_v = (signed char *)dest_y + m_xvImage->offsets[1],
163
+ *dest_u = (signed char *)dest_y + m_xvImage->offsets[2];
164
+ for ( int y=0; y<height; y+=2 ) {
165
+ for ( int x=0; x<width; x+=2 ) {
166
+ dest_y[ 0] = src_y[ 0];
167
+ dest_y[ 1] = src_y[ 1];
168
+ dest_y[m_xvImage->pitches[0] ] = src_y[widtha ];
169
+ dest_y[m_xvImage->pitches[0]+1] = src_y[widtha+1];
170
+ *dest_v = *src_v;
171
+ *dest_u = *src_u;
172
+ src_y += 2;
173
+ src_u++;
174
+ src_v++;
175
+ dest_y += 2;
176
+ dest_u++;
177
+ dest_v++;
178
+ };
179
+ src_y += 2 * widtha - width;
180
+ src_v += width2a - width2;
181
+ src_u += width2a - width2;
182
+ dest_y += 2 * m_xvImage->pitches[0] - width;
183
+ dest_v += m_xvImage->pitches[1] - width2;
184
+ dest_u += m_xvImage->pitches[2] - width2;
185
+ };
186
+ retVal = dest;
187
+ } else
188
+ retVal = frame;
189
+ return retVal;
190
+ }
191
+
192
+ int XVideoImagePainter::typecodeToUID( string typecode )
193
+ {
194
+ map< string, int > uid;
195
+ uid[ "UBYTERGB" ] = 0x20424752;
196
+ uid[ "YV12" ] = 0x32315659;
197
+ uid[ "I420" ] = 0x30323449;
198
+ map< string, int >::iterator i = uid.find( typecode );
199
+ int retVal = 0;
200
+ if ( i != uid.end() ) retVal = i->second;
201
+ #ifndef NDEBUG
202
+ if ( retVal != 0 )
203
+ cerr << "uid for \"" << typecode << "\" is 0x"
204
+ << setbase( 16 ) << retVal << setbase( 10 ) << endl;
205
+ else
206
+ cerr << "uid for \"" << typecode << "\" was not found";
207
+ #endif
208
+ return retVal;
209
+ }
210
+
211
+ string XVideoImagePainter::uidToTypecode( int uid )
212
+ {
213
+ map< int, string > typecode;
214
+ typecode[ 0x20424752 ] = "UBYTERGB";
215
+ typecode[ 0x32315659 ] = "YV12";
216
+ typecode[ 0x30323449 ] = "I420";
217
+ map< int, string >::iterator i = typecode.find( uid );
218
+ string retVal = "";
219
+ if ( i != typecode.end() ) retVal = i->second;
220
+ #ifndef NDEBUG
221
+ if ( retVal != "" )
222
+ cerr << "0x" << setbase( 16 ) << uid << setbase( 10 )
223
+ << " designates colourspace \"" << retVal << "\"" << endl;
224
+ else
225
+ cerr << "0x" << setbase( 16 ) << uid << setbase( 10 )
226
+ << " does not designate a known colourspace" << endl;
227
+ #endif
228
+ return retVal;
229
+ }
230
+
231
+ void XVideoImagePainter::unregisterWindow(void)
232
+ {
233
+ if ( m_port != 0 ) {
234
+ XvUngrabPort( m_display->get(), m_port, CurrentTime );
235
+ grabbedPorts.erase( m_port );
236
+ };
237
+ m_port = 0;
238
+ X11Painter::unregisterWindow();
239
+ }
240
+
241
+ XVisualInfo *XVideoImagePainter::visualInfo( X11DisplayPtr display )
242
+ throw (Error)
243
+ {
244
+ // Integrated GPL licensed code from MPlayer (http://www.mplayerhq.hu/).
245
+ m_display = display;
246
+ int depth;
247
+ {
248
+ XWindowAttributes attributes;
249
+ XGetWindowAttributes( display->get(),
250
+ DefaultRootWindow( display->get() ),
251
+ &attributes );
252
+ #ifndef NDEBUG
253
+ cerr << "Colour depth is " << attributes.depth << '.' << endl;
254
+ #endif
255
+ switch ( attributes.depth ) {
256
+ case 15:
257
+ case 16:
258
+ case 24:
259
+ case 32:
260
+ depth = attributes.depth;
261
+ break;
262
+ default:
263
+ depth = 24;
264
+ };
265
+ };
266
+ #ifndef NDEBUG
267
+ cerr << "Trying colour depth " << depth << '.' << endl;
268
+ #endif
269
+ ERRORMACRO( XMatchVisualInfo( display->get(),
270
+ DefaultScreen( display->get() ), depth,
271
+ TrueColor, &m_visualInfo ) != 0,
272
+ Error, , "Could not find suitable true colour visual." );
273
+ {
274
+ unsigned int ver, rel, req, ev, err;
275
+ ERRORMACRO( XvQueryExtension( display->get(), &ver, &rel, &req, &ev,
276
+ &err ) == Success, Error, ,
277
+ "Failure requesting X video extension" );
278
+ }
279
+ unsigned int numAdaptors;
280
+ XvAdaptorInfo *adaptorInfo = NULL;
281
+ ERRORMACRO( XvQueryAdaptors( display->get(),
282
+ DefaultRootWindow( display->get() ),
283
+ &numAdaptors, &adaptorInfo ) == Success,
284
+ Error, , "Error requesting information about X video "
285
+ "adaptors." );
286
+ for ( int i=0; i<(signed)numAdaptors; i++ ) {
287
+ if ( ( adaptorInfo[i].type & ( XvInputMask | XvImageMask ) ) ==
288
+ ( XvInputMask | XvImageMask ) ) {
289
+ for ( int p=adaptorInfo[i].base_id;
290
+ p<(signed)(adaptorInfo[i].base_id+adaptorInfo[i].num_ports);
291
+ p++ )
292
+ // API does not seem to protect against grabbing a port
293
+ // twice (from within the same process).
294
+ if ( grabbedPorts.find( p ) == grabbedPorts.end() ) {
295
+ if ( XvGrabPort( display->get(), p, CurrentTime ) == Success ) {
296
+ #ifndef NDEBUG
297
+ cerr << "Grabbed port " << p << endl;
298
+ #endif
299
+ grabbedPorts.insert( p );
300
+ m_port = p;
301
+ break;
302
+ };
303
+ };
304
+ if ( m_port != 0 )
305
+ break;
306
+ };
307
+ };
308
+ XvFreeAdaptorInfo( adaptorInfo );
309
+ ERRORMACRO( m_port != 0, Error, ,
310
+ "Could not grab a free port for X video output." );
311
+ try {
312
+
313
+ Atom xvColourKey = findAtom( "XV_COLORKEY" );
314
+ if ( xvColourKey != None ) {
315
+ #ifndef NDEBUG
316
+ cerr << "Require drawing of colourkey." << endl;
317
+ #endif
318
+ m_requireColourKey = true;
319
+ ERRORMACRO( XvGetPortAttribute( display->get(), m_port, xvColourKey,
320
+ &m_colourKey ) == Success,
321
+ Error, , "Error reading value of colour-key." );
322
+ #ifndef NDEBUG
323
+ cerr << "Colour-key is 0x" << setw( 6 ) << setbase( 16 )
324
+ << m_colourKey << setbase( 10 ) << setw( 0 ) << endl;
325
+ #endif
326
+ Atom xvAutoPaint = findAtom( "XV_AUTOPAINT_COLORKEY" );
327
+ if ( xvAutoPaint != None ) {
328
+ #ifndef NDEBUG
329
+ cerr << "Disabling autopainting." << endl;
330
+ #endif
331
+ XvSetPortAttribute( display->get(), m_port, xvAutoPaint, 0 );
332
+ } else {
333
+ #ifndef NDEBUG
334
+ cerr << "Graphic card does not provide autopainting." << endl;
335
+ #endif
336
+ };
337
+ } else {
338
+ m_requireColourKey = false;
339
+ #ifndef NDEBUG
340
+ cerr << "No drawing of colourkey required." << endl;
341
+ #endif
342
+ };
343
+
344
+ } catch ( Error &e ) {
345
+
346
+ XvUngrabPort( display->get(), m_port, CurrentTime );
347
+ grabbedPorts.erase( m_port );
348
+ throw e;
349
+
350
+ };
351
+ return &m_visualInfo;
352
+ }
353
+
354
+ Atom XVideoImagePainter::findAtom( const char *name ) throw (Error)
355
+ {
356
+ // Integrated GPL-licensed code from MPlayer (http://www.mplayerhq.hu/).
357
+ assert( m_display );
358
+ assert( m_port != 0 );
359
+ XvAttribute *attributes;
360
+ int numAttributes;
361
+ attributes = XvQueryPortAttributes( m_display->get(), m_port,
362
+ &numAttributes );
363
+ ERRORMACRO( attributes != NULL, Error, ,
364
+ "Error requesting attributes of X video port." );
365
+ Atom retVal = None;
366
+ for ( int i=0; i<numAttributes; i++ )
367
+ if ( strcmp( attributes[i].name, name ) == 0 ) {
368
+ retVal = XInternAtom( m_display->get(), name, False );
369
+ break;
370
+ }
371
+ XFree( attributes );
372
+ return retVal;
373
+ }
374
+
375
+ int XVideoImagePainter::selectFormat( const int preferredUID ) throw (Error)
376
+ {
377
+ // Integrated GPL-licensed code from MPlayer (http://www.mplayerhq.hu/).
378
+ assert( m_display );
379
+ assert( m_port != 0 );
380
+ XvImageFormatValues *formats;
381
+ int numFormats;
382
+ formats = XvListImageFormats( m_display->get(), m_port, &numFormats );
383
+ ERRORMACRO( formats != NULL, Error, ,
384
+ "Error requesting list of image formats." );
385
+ #ifndef NDEBUG
386
+ for ( int i=0; i<numFormats; i++ ) {
387
+ int id = formats[i].id;
388
+ cerr << "format 0x" << setbase( 16 ) << id << setbase( 10 ) << ": '";
389
+ cerr << (char)( id & 0xFF )
390
+ << (char)( ( id >> 8 ) & 0xFF )
391
+ << (char)( ( id >> 16 ) & 0xFF )
392
+ << (char)( ( id >> 24 ) & 0xFF ) << "'";
393
+ if ( formats[i].format == XvPacked )
394
+ cerr << "(packed)" << endl;
395
+ else
396
+ cerr << "(planar)" << endl;
397
+ };
398
+ #endif
399
+ int retVal = 0;
400
+ for ( int i=0; i<numFormats; i++ )
401
+ if ( formats[i].id == preferredUID && preferredUID != 0 ) {
402
+ #ifndef NDEBUG
403
+ cerr << "Found XVideo support for preferred colourspace ";
404
+ cerr << "0x" << setbase( 16 ) << preferredUID << setbase( 10 ) << endl;
405
+ #endif
406
+ retVal = preferredUID;
407
+ break;
408
+ } else if ( retVal == 0 && uidToTypecode( formats[i].id ) != "" ) {
409
+ #ifndef NDEBUG
410
+ cerr << "Selecting \"" << uidToTypecode( formats[i].id )
411
+ << "\" as colourspace for fallback" << endl;
412
+ #endif
413
+ retVal = formats[i].id;
414
+ }
415
+ return retVal;
416
+ }
417
+
418
+ VALUE XVideoImagePainter::registerRubyClass( VALUE module,
419
+ VALUE cX11Output )
420
+ {
421
+ cRubyClass = rb_define_class_under( module, "XVideoOutput", cX11Output );
422
+ rbHornetseye = module;
423
+ rb_define_singleton_method( cRubyClass, "new",
424
+ RUBY_METHOD_FUNC( wrapNew ), 0 );
425
+ return cRubyClass;
426
+ }
427
+
428
+ VALUE XVideoImagePainter::wrapNew( VALUE rbClass )
429
+ {
430
+ VALUE retVal = Qnil;
431
+ X11PainterPtr painter( new XVideoImagePainter );
432
+ X11OutputPtr ptr( new X11Output( painter ) );
433
+ retVal = Data_Wrap_Struct( rbClass,
434
+ X11Output::markRubyObject,
435
+ X11Output::deleteRubyObject,
436
+ new X11OutputPtr( ptr ) );
437
+ return retVal;
438
+ }
439
+