hornetseye-qt4 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/rubytools.hh ADDED
@@ -0,0 +1,33 @@
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 HORNETSEYE_RUBYTOOLS_HH
17
+ #define HORNETSEYE_RUBYTOOLS_HH
18
+
19
+ #include <complex>
20
+ #include "rubyinc.hh"
21
+
22
+ void checkType( VALUE rbValue, VALUE rbClass );
23
+
24
+ void checkStruct( VALUE rbValue, VALUE rbClass );
25
+
26
+ #define dataGetStruct(obj,klass,type,sval) { \
27
+ checkStruct( obj, klass ); \
28
+ Data_Get_Struct( obj, type, sval ); \
29
+ }
30
+
31
+ #include "rubytools.tcc"
32
+
33
+ #endif
data/ext/rubytools.tcc ADDED
@@ -0,0 +1,32 @@
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
+ #include <cassert>
17
+ #include "error.hh"
18
+
19
+ inline void checkType( VALUE rbValue, VALUE rbClass )
20
+ {
21
+ ERRORMACRO( rb_funcall( rbValue, rb_intern( "kind_of?" ), 1, rbClass ) ==
22
+ Qtrue, Error, ,
23
+ "Argument must be of class \"" << rb_class2name( rbClass )
24
+ << "\"." );
25
+ }
26
+
27
+ inline void checkStruct( VALUE rbValue, VALUE rbClass )
28
+ {
29
+ Check_Type( rbValue, T_DATA );
30
+ checkType( rbValue, rbClass );
31
+ }
32
+
data/ext/xvwidget.cc ADDED
@@ -0,0 +1,501 @@
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 NDEBUG
17
+ #include <iostream>
18
+ #include <iomanip>
19
+ #endif
20
+
21
+ using namespace std;
22
+
23
+ #include <QtCore/QCoreApplication>
24
+ #include <QtGui/QX11Info>
25
+ #include "rubytools.hh"
26
+ #include "xvwidget.hh"
27
+
28
+ // also see xvideoimagepainter.cc
29
+
30
+ std::map< VALUE, XvManagerPtr > xvManager;
31
+
32
+ VALUE XvManager::cRubyClass = Qnil;
33
+ VALUE XvManager::rbHornetseye = Qnil;
34
+
35
+ std::set< XvPortID > XvManager::grabbedPorts;
36
+
37
+ XvManager::XvManager( QWidget *widget ):
38
+ m_widget(widget), m_port(0), m_requireColourKey(false), m_colourKey(0),
39
+ m_xvImage(NULL)
40
+ {
41
+ m_widget->setAttribute( Qt::WA_NoSystemBackground );
42
+ m_widget->setAttribute( Qt::WA_OpaquePaintEvent );
43
+ m_widget->setAttribute( Qt::WA_PaintOnScreen );
44
+ m_widget->setAutoFillBackground( false );
45
+ }
46
+
47
+ void XvManager::paint(void) throw (Error)
48
+ {
49
+ Display *display = m_widget->x11Info().display();
50
+ ERRORMACRO( display != NULL, Error, ,
51
+ "Connection to X server does not exist" );
52
+ int id = m_widget->winId();
53
+ XGCValues xgcv;
54
+ GC gc = XCreateGC( display, id, 0L, &xgcv );
55
+ if ( m_xvImage != NULL ) {
56
+ if ( m_requireColourKey ) {
57
+ XSetForeground( display, gc, m_colourKey );
58
+ XFillRectangle( display, id, gc, 0, 0,
59
+ m_widget->width(), m_widget->height() );
60
+ };
61
+ } else {
62
+ XSetForeground( display, gc, 0 );
63
+ XFillRectangle( display, id, gc, 0, 0,
64
+ m_widget->width(), m_widget->height() );
65
+ };
66
+ XFreeGC( display, gc );
67
+ }
68
+
69
+ void XvManager::grabPort(void) throw (Error)
70
+ {
71
+ if ( m_port == 0 ) {
72
+ // check whether m_port is zero !!!
73
+ Display *display = m_widget->x11Info().display();
74
+ ERRORMACRO( display != NULL, Error, ,
75
+ "Connection to X server does not exist" );
76
+ unsigned int ver, rel, req, ev, err;
77
+ ERRORMACRO( XvQueryExtension( display, &ver, &rel, &req, &ev,
78
+ &err ) == Success, Error, ,
79
+ "Failure requesting X video extension" );
80
+ unsigned int numAdaptors;
81
+ XvAdaptorInfo *adaptorInfo = NULL;
82
+ ERRORMACRO( XvQueryAdaptors( display,
83
+ DefaultRootWindow( display ),// correct? !!!
84
+ &numAdaptors, &adaptorInfo ) == Success,
85
+ Error, , "Error requesting information about X video "
86
+ "adaptors." );
87
+ for ( int i=0; i<(signed)numAdaptors; i++ ) {
88
+ if ( ( adaptorInfo[i].type & ( XvInputMask | XvImageMask ) ) ==
89
+ ( XvInputMask | XvImageMask ) ) {
90
+ for ( int p=adaptorInfo[i].base_id;
91
+ p<(signed)(adaptorInfo[i].base_id+adaptorInfo[i].num_ports);
92
+ p++ )
93
+ // API does not seem to protect against grabbing a port
94
+ // twice (from within the same process).
95
+ if ( grabbedPorts.find( p ) == grabbedPorts.end() ) {
96
+ if ( XvGrabPort( display, p, CurrentTime ) == Success ) {
97
+ #ifndef NDEBUG
98
+ cerr << "Grabbed port " << p << endl;
99
+ #endif
100
+ grabbedPorts.insert( p );
101
+ m_port = p;
102
+ break;
103
+ };
104
+ };
105
+ if ( m_port != 0 )
106
+ break;
107
+ };
108
+ };
109
+ XvFreeAdaptorInfo( adaptorInfo );
110
+ ERRORMACRO( m_port != 0, Error, ,
111
+ "Could not grab a free port for X video output." );
112
+ try {
113
+ Atom xvColourKey = findAtom( display, "XV_COLORKEY" );
114
+ if ( xvColourKey != None ) {
115
+ #ifndef NDEBUG
116
+ cerr << "Require drawing of colourkey." << endl;
117
+ #endif
118
+ m_requireColourKey = true;
119
+ ERRORMACRO( XvGetPortAttribute( display, m_port, xvColourKey,
120
+ &m_colourKey ) == Success,
121
+ Error, , "Error reading value of colour-key." );
122
+ #ifndef NDEBUG
123
+ cerr << "Colour-key is 0x" << setw( 6 ) << setbase( 16 )
124
+ << m_colourKey << setbase( 10 ) << setw( 0 ) << endl;
125
+ #endif
126
+ Atom xvAutoPaint = findAtom( display, "XV_AUTOPAINT_COLORKEY" );
127
+ if ( xvAutoPaint != None ) {
128
+ #ifndef NDEBUG
129
+ cerr << "Disabling autopainting." << endl;
130
+ #endif
131
+ XvSetPortAttribute( display, m_port, xvAutoPaint, 0 );
132
+ } else {
133
+ #ifndef NDEBUG
134
+ cerr << "Graphic card does not provide autopainting." << endl;
135
+ #endif
136
+ };
137
+ } else {
138
+ m_requireColourKey = false;
139
+ #ifndef NDEBUG
140
+ cerr << "No drawing of colourkey required." << endl;
141
+ #endif
142
+ };
143
+
144
+ } catch ( Error &e ) {
145
+
146
+ XvUngrabPort( display, m_port, CurrentTime );
147
+ grabbedPorts.erase( m_port );
148
+ throw e;
149
+
150
+ };
151
+ };
152
+ }
153
+
154
+ void XvManager::releasePort(void)
155
+ {
156
+ clear();
157
+ if ( m_port != 0 ) {
158
+ Display *display = m_widget->x11Info().display();
159
+ if ( display != NULL )
160
+ XvUngrabPort( display, m_port, CurrentTime );
161
+ grabbedPorts.erase( m_port );
162
+ };
163
+ }
164
+
165
+ void XvManager::clear(void)
166
+ {
167
+ if ( m_xvImage != NULL ) {
168
+ XFree( m_xvImage );
169
+ m_xvImage = NULL;
170
+ m_widget->update();
171
+ };
172
+ }
173
+
174
+ void XvManager::write( FramePtr frame ) throw (Error)
175
+ {
176
+ Display *display = m_widget->x11Info().display();
177
+ ERRORMACRO( display != NULL, Error, ,
178
+ "Connection to X server does not exist" );
179
+ ERRORMACRO( m_port != 0, Error, ,
180
+ "Need to grab XVideo port before image can be displayed." );
181
+ if ( frame ) {
182
+ #ifndef NDEBUG
183
+ cerr << "XVideo-output for \"" << frame->typecode() << "\"." << endl;
184
+ #endif
185
+ int uid = selectFormat( display, typecodeToUID( frame->typecode() ) );
186
+ ERRORMACRO( uid != 0, Error, , "XVideo-extension does not "
187
+ "support YV12, I420, or RGB24" );
188
+ string typecode = uidToTypecode( uid );
189
+ if ( frame->typecode() != typecode ) {
190
+ VALUE
191
+ rbTypecode = rb_funcall( rbHornetseye, rb_intern( "const_get" ), 1,
192
+ rb_str_new( typecode.c_str(),
193
+ typecode.length() ) ),
194
+ rbFrame = rb_funcall( frame->rubyObject(), rb_intern( "to_type" ), 1,
195
+ rbTypecode );
196
+ frame = FramePtr( new Frame( rbFrame ) );
197
+ };
198
+ if ( m_xvImage != NULL ) {
199
+ if ( m_xvImage->id != uid ||
200
+ m_xvImage->width != frame->width() ||
201
+ m_xvImage->height != frame->height() ) {
202
+ XFree( m_xvImage );
203
+ m_xvImage = NULL;
204
+ };
205
+ };
206
+ if ( m_xvImage == NULL ) {
207
+ m_xvImage =
208
+ XvCreateImage( display, m_port, uid,
209
+ (char *)frame->data(),
210
+ frame->width(), frame->height() );
211
+ m_widget->update();
212
+ #ifndef NDEBUG
213
+ cerr << "Created " << m_xvImage->width << 'x'
214
+ << m_xvImage->height << ' ' << frame->typecode()
215
+ << "-image for X video." << endl;
216
+ cerr << "# planes = " << m_xvImage->num_planes << endl;
217
+ for ( int i=0; i<m_xvImage->num_planes; i++ )
218
+ cerr << "offsets[" << i << "]=" << m_xvImage->offsets[i]
219
+ << endl
220
+ << "pitches[" << i << "]=" << m_xvImage->pitches[i]
221
+ << endl;
222
+ #endif
223
+ } else
224
+ m_xvImage->data = (char *)frame->data();
225
+ if ( frame->typecode() == "YV12" ) {
226
+ // YV12 requires alignment for X video output.
227
+ frame = alignYV12( frame );
228
+ m_xvImage->data = (char *)frame->data();
229
+ };
230
+ XGCValues xgcv;
231
+ int id = m_widget->winId();
232
+ GC gc = XCreateGC( display, id, 0L, &xgcv );
233
+ XvPutImage( display, m_port, id,
234
+ gc, m_xvImage, 0, 0,
235
+ m_xvImage->width, m_xvImage->height, 0, 0,
236
+ m_widget->width(), m_widget->height() );
237
+ XFreeGC( display, gc );
238
+ };
239
+ }
240
+
241
+ int XvManager::selectFormat( Display *display, const int preferredUID )
242
+ throw (Error)
243
+ {
244
+ // Integrated GPL-licensed code from MPlayer (http://www.mplayerhq.hu/).
245
+ assert( m_port != 0 );
246
+ XvImageFormatValues *formats;
247
+ int numFormats;
248
+ formats = XvListImageFormats( display, m_port, &numFormats );
249
+ ERRORMACRO( formats != NULL, Error, ,
250
+ "Error requesting list of image formats." );
251
+ #ifndef NDEBUG
252
+ for ( int i=0; i<numFormats; i++ ) {
253
+ int id = formats[i].id;
254
+ cerr << "format 0x" << setbase( 16 ) << id << setbase( 10 ) << ": '";
255
+ cerr << (char)( id & 0xFF )
256
+ << (char)( ( id >> 8 ) & 0xFF )
257
+ << (char)( ( id >> 16 ) & 0xFF )
258
+ << (char)( ( id >> 24 ) & 0xFF ) << "'";
259
+ if ( formats[i].format == XvPacked )
260
+ cerr << "(packed)" << endl;
261
+ else
262
+ cerr << "(planar)" << endl;
263
+ };
264
+ #endif
265
+ int retVal = 0;
266
+ for ( int i=0; i<numFormats; i++ )
267
+ if ( formats[i].id == preferredUID && preferredUID != 0 ) {
268
+ #ifndef NDEBUG
269
+ cerr << "Found XVideo support for preferred colourspace ";
270
+ cerr << "0x" << setbase( 16 ) << preferredUID << setbase( 10 ) << endl;
271
+ #endif
272
+ retVal = preferredUID;
273
+ break;
274
+ } else if ( retVal == 0 && uidToTypecode( formats[i].id ) != "" ) {
275
+ #ifndef NDEBUG
276
+ cerr << "Selecting \"" << uidToTypecode( formats[i].id )
277
+ << "\" as colourspace for fallback" << endl;
278
+ #endif
279
+ retVal = formats[i].id;
280
+ }
281
+ return retVal;
282
+ }
283
+
284
+ Atom XvManager::findAtom( Display *display, const char *name ) throw (Error)
285
+ {
286
+ // Integrated GPL-licensed code from MPlayer (http://www.mplayerhq.hu/).
287
+ assert( m_port != 0 );
288
+ XvAttribute *attributes;
289
+ int numAttributes;
290
+ attributes = XvQueryPortAttributes( display, m_port,
291
+ &numAttributes );
292
+ ERRORMACRO( attributes != NULL, Error, ,
293
+ "Error requesting attributes of X video port." );
294
+ Atom retVal = None;
295
+ for ( int i=0; i<numAttributes; i++ )
296
+ if ( strcmp( attributes[i].name, name ) == 0 ) {
297
+ retVal = XInternAtom( display, name, False );
298
+ break;
299
+ }
300
+ XFree( attributes );
301
+ return retVal;
302
+ }
303
+
304
+ FramePtr XvManager::alignYV12( FramePtr frame )
305
+ {
306
+ // YV12-images aligned by Xine sometimes do not fit the required
307
+ // output.
308
+ assert( m_xvImage != NULL );
309
+ int
310
+ width = frame->width(),
311
+ height = frame->height(),
312
+ width2 = ( width + 1 ) / 2,
313
+ height2 = ( height + 1 ) / 2,
314
+ widtha = ( width + 7 ) & ~0x7,
315
+ width2a = ( width2 + 7 ) & ~0x7;
316
+ assert( m_xvImage->offsets[0] == 0 );
317
+ FramePtr retVal;
318
+ if ( m_xvImage->offsets[1] != widtha * height ||
319
+ m_xvImage->offsets[2] != widtha * height + width2a * height2 ||
320
+ m_xvImage->pitches[0] != widtha ||
321
+ m_xvImage->pitches[1] != width2a ||
322
+ m_xvImage->pitches[2] != width2a ) {
323
+ #ifndef NDEBUG
324
+ cerr << "YV12-Image needs alignment." << endl;
325
+ #endif
326
+ FramePtr dest( new Frame( "YV12",
327
+ m_xvImage->width, m_xvImage->height ) );
328
+ const char
329
+ *src_y = frame->data();
330
+ const signed char
331
+ *src_v = (const signed char *)src_y + widtha * height,
332
+ *src_u = src_v + width2a * height2;
333
+ unsigned char
334
+ *dest_y = (unsigned char *)dest->data();
335
+ signed char
336
+ *dest_v = (signed char *)dest_y + m_xvImage->offsets[1],
337
+ *dest_u = (signed char *)dest_y + m_xvImage->offsets[2];
338
+ for ( int y=0; y<height; y+=2 ) {
339
+ for ( int x=0; x<width; x+=2 ) {
340
+ dest_y[ 0] = src_y[ 0];
341
+ dest_y[ 1] = src_y[ 1];
342
+ dest_y[m_xvImage->pitches[0] ] = src_y[widtha ];
343
+ dest_y[m_xvImage->pitches[0]+1] = src_y[widtha+1];
344
+ *dest_v = *src_v;
345
+ *dest_u = *src_u;
346
+ src_y += 2;
347
+ src_u++;
348
+ src_v++;
349
+ dest_y += 2;
350
+ dest_u++;
351
+ dest_v++;
352
+ };
353
+ src_y += 2 * widtha - width;
354
+ src_v += width2a - width2;
355
+ src_u += width2a - width2;
356
+ dest_y += 2 * m_xvImage->pitches[0] - width;
357
+ dest_v += m_xvImage->pitches[1] - width2;
358
+ dest_u += m_xvImage->pitches[2] - width2;
359
+ };
360
+ retVal = dest;
361
+ } else
362
+ retVal = frame;
363
+ return retVal;
364
+ }
365
+
366
+ int XvManager::typecodeToUID( string typecode )
367
+ {
368
+ map< string, int > uid;
369
+ uid[ "UBYTERGB" ] = 0x20424752;
370
+ uid[ "YV12" ] = 0x32315659;
371
+ uid[ "I420" ] = 0x30323449;
372
+ map< string, int >::iterator i = uid.find( typecode );
373
+ int retVal = 0;
374
+ if ( i != uid.end() ) retVal = i->second;
375
+ #ifndef NDEBUG
376
+ if ( retVal != 0 )
377
+ cerr << "uid for \"" << typecode << "\" is 0x"
378
+ << setbase( 16 ) << retVal << setbase( 10 ) << endl;
379
+ else
380
+ cerr << "uid for \"" << typecode << "\" was not found";
381
+ #endif
382
+ return retVal;
383
+ }
384
+
385
+ string XvManager::uidToTypecode( int uid )
386
+ {
387
+ map< int, string > typecode;
388
+ typecode[ 0x20424752 ] = "UBYTERGB";
389
+ typecode[ 0x32315659 ] = "YV12";
390
+ typecode[ 0x30323449 ] = "I420";
391
+ map< int, string >::iterator i = typecode.find( uid );
392
+ string retVal = "";
393
+ if ( i != typecode.end() ) retVal = i->second;
394
+ #ifndef NDEBUG
395
+ if ( retVal != "" )
396
+ cerr << "0x" << setbase( 16 ) << uid << setbase( 10 )
397
+ << " designates colourspace \"" << retVal << "\"" << endl;
398
+ else
399
+ cerr << "0x" << setbase( 16 ) << uid << setbase( 10 )
400
+ << " does not designate a known colourspace" << endl;
401
+ #endif
402
+ return retVal;
403
+ }
404
+
405
+ VALUE XvManager::registerRubyClass( VALUE module, VALUE cWidget )
406
+ {
407
+ cRubyClass = rb_define_class_under( module, "XvWidget", cWidget );
408
+ rbHornetseye = module;
409
+ rb_define_singleton_method( cRubyClass, "register",
410
+ RUBY_METHOD_FUNC( XvManager::wrapRegister ),
411
+ 1 );
412
+ rb_define_singleton_method( cRubyClass, "unregister",
413
+ RUBY_METHOD_FUNC( XvManager::wrapUnregister ),
414
+ 1 );
415
+ rb_define_method( cRubyClass, "paintEvent",
416
+ RUBY_METHOD_FUNC( XvManager::wrapPaintEvent ), 1 );
417
+ rb_define_method( cRubyClass, "grabPort",
418
+ RUBY_METHOD_FUNC( XvManager::wrapGrabPort ), 0 );
419
+ rb_define_method( cRubyClass, "releasePort",
420
+ RUBY_METHOD_FUNC( XvManager::wrapReleasePort ), 0 );
421
+ rb_define_method( cRubyClass, "clear",
422
+ RUBY_METHOD_FUNC( XvManager::wrapClear ), 0 );
423
+ rb_define_method( cRubyClass, "write",
424
+ RUBY_METHOD_FUNC( XvManager::wrapWrite ), 1 );
425
+ return cRubyClass;
426
+ }
427
+
428
+ VALUE XvManager::wrapRegister( VALUE rbClass, VALUE rbWidget )
429
+ {
430
+ #ifndef NDEBUG
431
+ cerr << "Registering custom widget ... " << flush;
432
+ #endif
433
+ const char *name = "HORNETSEYE-XVWIDGETFISHING";
434
+ QObject object( QCoreApplication::instance() );
435
+ object.setObjectName( name );
436
+ VALUE rbQObject =
437
+ rb_eval_string( "Qt::CoreApplication.instance.findChild"
438
+ "( Qt::Object, 'HORNETSEYE-XVWIDGETFISHING' )" );
439
+ rb_funcall( rbQObject, rb_intern( "parent=" ), 1, rbWidget );
440
+ xvManager[ rbWidget ] =
441
+ XvManagerPtr( new XvManager( (QWidget *)object.parent() ) );
442
+ #ifndef NDEBUG
443
+ cerr << "done" << endl;
444
+ #endif
445
+ return rbWidget;
446
+ }
447
+
448
+ VALUE XvManager::wrapUnregister( VALUE rbClass, VALUE rbWidget )
449
+ {
450
+ xvManager.erase( rbWidget );
451
+ return rbWidget;
452
+ }
453
+
454
+ VALUE XvManager::wrapGrabPort( VALUE rbSelf )
455
+ {
456
+ try {
457
+ assert( xvManager[ rbSelf ] );
458
+ xvManager[ rbSelf ]->grabPort();
459
+ } catch ( std::exception &e ) {
460
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
461
+ }
462
+ return rbSelf;
463
+ }
464
+
465
+ VALUE XvManager::wrapReleasePort( VALUE rbSelf )
466
+ {
467
+ assert( xvManager[ rbSelf ] );
468
+ xvManager[ rbSelf ]->releasePort();
469
+ return rbSelf;
470
+ }
471
+
472
+ VALUE XvManager::wrapClear( VALUE rbSelf )
473
+ {
474
+ assert( xvManager[ rbSelf ] );
475
+ xvManager[ rbSelf ]->clear();
476
+ return rbSelf;
477
+ }
478
+
479
+ VALUE XvManager::wrapWrite( VALUE rbSelf, VALUE rbFrame )
480
+ {
481
+ try {
482
+ FramePtr frame( new Frame( rbFrame ) );
483
+ assert( xvManager[ rbSelf ] );
484
+ xvManager[ rbSelf ]->write( frame );
485
+ } catch ( std::exception &e ) {
486
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
487
+ }
488
+ return rbFrame;
489
+ }
490
+
491
+ VALUE XvManager::wrapPaintEvent( VALUE rbSelf, VALUE rbPaintEvent )
492
+ {
493
+ try {
494
+ assert( xvManager[ rbSelf ] );
495
+ xvManager[ rbSelf ]->paint();
496
+ } catch ( std::exception &e ) {
497
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
498
+ }
499
+ return rbSelf;
500
+ }
501
+