Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Version 0.1.0

  • Loading branch information...
commit 75825cf1aa037870a8d3a3bbd2fc225a2d06caf3 1 parent 4ca7273
@wedesoft authored
View
6 Rakefile
@@ -28,7 +28,7 @@ HOMEPAGE = %q{http://wedesoft.github.com/hornetseye-qt4/}
OBJ = CC_FILES.ext 'o'
$CXXFLAGS = ENV[ 'CXXFLAGS' ] || ''
-$CXXFLAGS = "#{$CXXFLAGS} -fPIC -DNDEBUG -DHAVE_CONFIG_H"
+$CXXFLAGS = "#{$CXXFLAGS} -fPIC -DNDEBUG -DQT_SHARED -I/usr/include/qt4"
if RbConfig::CONFIG[ 'rubyhdrdir' ]
$CXXFLAGS = "#{$CXXFLAGS} -I#{RbConfig::CONFIG[ 'rubyhdrdir' ]} " +
"-I#{RbConfig::CONFIG[ 'rubyhdrdir' ]}/#{RbConfig::CONFIG[ 'arch' ]}"
@@ -45,7 +45,7 @@ desc 'Compile Ruby extension (default)'
task :all => [ SO_FILE ]
file SO_FILE => OBJ do |t|
- sh "#{CXX} -shared -o #{t.name} #{OBJ} -lX11 -lXv #{$LIBRUBYARG}"
+ sh "#{CXX} -shared -o #{t.name} #{OBJ} -lX11 -lXv -lQtGui -lQtCore #{$LIBRUBYARG}"
sh "#{STRIP} --strip-all #{t.name}"
end
@@ -114,6 +114,7 @@ begin
s.has_rdoc = 'yard'
s.extra_rdoc_files = []
s.rdoc_options = %w{--no-private}
+ s.add_dependency %<qtruby4>, [ '~> 2.1' ]
s.add_dependency %<malloc>, [ '~> 1.1' ]
s.add_dependency %<multiarray>, [ '~> 0.9' ]
s.add_dependency %<hornetseye-frame>, [ '~> 0.6' ]
@@ -137,6 +138,7 @@ begin
s.has_rdoc = 'yard'
s.extra_rdoc_files = []
s.rdoc_options = %w{--no-private}
+ s.add_dependency %<qtruby4>, [ '~> 2.1' ]
s.add_dependency %<malloc>, [ '~> 1.1' ]
s.add_dependency %<multiarray>, [ '~> 0.9' ]
s.add_dependency %<hornetseye-frame>, [ '~> 0.6' ]
View
50 ext/error.hh
@@ -0,0 +1,50 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef ERROR_HH
+#define ERROR_HH
+
+#include <exception>
+#include <sstream>
+
+class Error: public std::exception
+{
+public:
+ Error(void) {}
+ Error( Error &e ): std::exception( e )
+ { m_message << e.m_message.str(); }
+ virtual ~Error(void) throw() {}
+ template< typename T >
+ std::ostream &operator<<( const T &t )
+ { m_message << t; return m_message; }
+ std::ostream &operator<<( std::ostream& (*__pf)(std::ostream&) )
+ { (*__pf)( m_message ); return m_message; }
+ virtual const char* what(void) const throw() {
+ temp = m_message.str();
+ return temp.c_str();
+ }
+protected:
+ std::ostringstream m_message;
+ mutable std::string temp;
+};
+
+#define ERRORMACRO( condition, class, params, message ) \
+ if ( !( condition ) ) { \
+ class _e params; \
+ _e << message; \
+ throw _e; \
+ };
+
+#endif
View
81 ext/frame.cc
@@ -0,0 +1,81 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "frame.hh"
+
+using namespace std;
+
+Frame::Frame( const string &typecode, int width, int height, char *data ):
+ m_frame( Qnil )
+{
+ VALUE mModule = rb_define_module( "Hornetseye" );
+ VALUE cMalloc = rb_define_class_under( mModule, "Malloc", rb_cObject );
+ VALUE cFrame = rb_define_class_under( mModule, "Frame", rb_cObject );
+ VALUE rbSize = INT2NUM( storageSize( typecode, width, height ) );
+ VALUE rbMemory;
+ if ( data != NULL ) {
+ rbMemory = Data_Wrap_Struct( cMalloc, 0, 0, (void *)data );
+ rb_ivar_set( rbMemory, rb_intern( "@size" ), rbSize );
+ } else
+ rbMemory = rb_funcall( cMalloc, rb_intern( "new" ), 1, rbSize );
+ m_frame = rb_funcall( cFrame, rb_intern( "import" ), 4,
+ rb_const_get( mModule, rb_intern( typecode.c_str() ) ),
+ INT2NUM( width ), INT2NUM( height ), rbMemory );
+}
+
+string Frame::typecode(void)
+{
+ VALUE rbString = rb_funcall( rb_funcall( m_frame, rb_intern( "typecode" ), 0 ),
+ rb_intern( "to_s" ), 0 );
+ return StringValuePtr( rbString );
+}
+
+int Frame::width(void)
+{
+ return NUM2INT( rb_funcall( m_frame, rb_intern( "width" ), 0 ) );
+}
+
+int Frame::height(void)
+{
+ return NUM2INT( rb_funcall( m_frame, rb_intern( "height" ), 0 ) );
+}
+
+char *Frame::data(void)
+{
+ VALUE rbMemory = rb_funcall( m_frame, rb_intern( "memory" ), 0 );
+ char *ptr;
+ Data_Get_Struct( rbMemory, char, ptr );
+ return ptr;
+}
+
+bool Frame::rgb(void)
+{
+ return rb_funcall( m_frame, rb_intern( "rgb?" ), 0 ) != Qfalse;
+}
+
+void Frame::markRubyMember(void)
+{
+ rb_gc_mark( m_frame );
+}
+
+int Frame::storageSize( const std::string &typecode, int width, int height )
+{
+ VALUE mModule = rb_define_module( "Hornetseye" );
+ VALUE cFrame = rb_define_class_under( mModule, "Frame", rb_cObject );
+ return NUM2INT( rb_funcall( cFrame, rb_intern( "storage_size" ), 3,
+ rb_const_get( mModule, rb_intern( typecode.c_str() ) ),
+ INT2NUM( width ), INT2NUM( height ) ) );
+}
+
View
43 ext/frame.hh
@@ -0,0 +1,43 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef FRAME_HH
+#define FRAME_HH
+
+#include <boost/smart_ptr.hpp>
+#include "rubyinc.hh"
+#include <string>
+
+class Frame
+{
+public:
+ Frame( const std::string &typecode, int width, int height, char *data = NULL );
+ Frame( VALUE rbFrame ): m_frame( rbFrame ) {}
+ virtual ~Frame(void) {}
+ std::string typecode(void);
+ int width(void);
+ int height(void);
+ char *data(void);
+ bool rgb(void);
+ VALUE rubyObject(void) { return m_frame; }
+ void markRubyMember(void);
+ static int storageSize( const std::string &typecode, int width, int height );
+protected:
+ VALUE m_frame;
+};
+
+typedef boost::shared_ptr< Frame > FramePtr;
+
+#endif
View
5 ext/init.cc
@@ -14,6 +14,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "rubyinc.hh"
+#include "xvwidget.hh"
#ifdef WIN32
#define DLLEXPORT __declspec(dllexport)
@@ -31,7 +32,11 @@ extern "C" {
{
// XInitThreads();
rb_require( "hornetseye_frame" );
+ rb_require( "Qt4" );
VALUE rbHornetseye = rb_define_module( "Hornetseye" );
+ VALUE rbQt = rb_define_module( "Qt" );
+ VALUE cWidget = rb_const_get( rbQt, rb_intern( "Widget" ) );
+ XvManager::registerRubyClass( rbHornetseye, cWidget );
rb_require( "hornetseye_qt4_ext.rb" );
}
View
33 ext/rubytools.hh
@@ -0,0 +1,33 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef HORNETSEYE_RUBYTOOLS_HH
+#define HORNETSEYE_RUBYTOOLS_HH
+
+#include <complex>
+#include "rubyinc.hh"
+
+void checkType( VALUE rbValue, VALUE rbClass );
+
+void checkStruct( VALUE rbValue, VALUE rbClass );
+
+#define dataGetStruct(obj,klass,type,sval) { \
+ checkStruct( obj, klass ); \
+ Data_Get_Struct( obj, type, sval ); \
+}
+
+#include "rubytools.tcc"
+
+#endif
View
32 ext/rubytools.tcc
@@ -0,0 +1,32 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include <cassert>
+#include "error.hh"
+
+inline void checkType( VALUE rbValue, VALUE rbClass )
+{
+ ERRORMACRO( rb_funcall( rbValue, rb_intern( "kind_of?" ), 1, rbClass ) ==
+ Qtrue, Error, ,
+ "Argument must be of class \"" << rb_class2name( rbClass )
+ << "\"." );
+}
+
+inline void checkStruct( VALUE rbValue, VALUE rbClass )
+{
+ Check_Type( rbValue, T_DATA );
+ checkType( rbValue, rbClass );
+}
+
View
501 ext/xvwidget.cc
@@ -0,0 +1,501 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007, 2008, 2009 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef NDEBUG
+#include <iostream>
+#include <iomanip>
+#endif
+
+using namespace std;
+
+#include <QtCore/QCoreApplication>
+#include <QtGui/QX11Info>
+#include "rubytools.hh"
+#include "xvwidget.hh"
+
+// also see xvideoimagepainter.cc
+
+std::map< VALUE, XvManagerPtr > xvManager;
+
+VALUE XvManager::cRubyClass = Qnil;
+VALUE XvManager::rbHornetseye = Qnil;
+
+std::set< XvPortID > XvManager::grabbedPorts;
+
+XvManager::XvManager( QWidget *widget ):
+ m_widget(widget), m_port(0), m_requireColourKey(false), m_colourKey(0),
+ m_xvImage(NULL)
+{
+ m_widget->setAttribute( Qt::WA_NoSystemBackground );
+ m_widget->setAttribute( Qt::WA_OpaquePaintEvent );
+ m_widget->setAttribute( Qt::WA_PaintOnScreen );
+ m_widget->setAutoFillBackground( false );
+}
+
+void XvManager::paint(void) throw (Error)
+{
+ Display *display = m_widget->x11Info().display();
+ ERRORMACRO( display != NULL, Error, ,
+ "Connection to X server does not exist" );
+ int id = m_widget->winId();
+ XGCValues xgcv;
+ GC gc = XCreateGC( display, id, 0L, &xgcv );
+ if ( m_xvImage != NULL ) {
+ if ( m_requireColourKey ) {
+ XSetForeground( display, gc, m_colourKey );
+ XFillRectangle( display, id, gc, 0, 0,
+ m_widget->width(), m_widget->height() );
+ };
+ } else {
+ XSetForeground( display, gc, 0 );
+ XFillRectangle( display, id, gc, 0, 0,
+ m_widget->width(), m_widget->height() );
+ };
+ XFreeGC( display, gc );
+}
+
+void XvManager::grabPort(void) throw (Error)
+{
+ if ( m_port == 0 ) {
+ // check whether m_port is zero !!!
+ Display *display = m_widget->x11Info().display();
+ ERRORMACRO( display != NULL, Error, ,
+ "Connection to X server does not exist" );
+ unsigned int ver, rel, req, ev, err;
+ ERRORMACRO( XvQueryExtension( display, &ver, &rel, &req, &ev,
+ &err ) == Success, Error, ,
+ "Failure requesting X video extension" );
+ unsigned int numAdaptors;
+ XvAdaptorInfo *adaptorInfo = NULL;
+ ERRORMACRO( XvQueryAdaptors( display,
+ DefaultRootWindow( display ),// correct? !!!
+ &numAdaptors, &adaptorInfo ) == Success,
+ Error, , "Error requesting information about X video "
+ "adaptors." );
+ for ( int i=0; i<(signed)numAdaptors; i++ ) {
+ if ( ( adaptorInfo[i].type & ( XvInputMask | XvImageMask ) ) ==
+ ( XvInputMask | XvImageMask ) ) {
+ for ( int p=adaptorInfo[i].base_id;
+ p<(signed)(adaptorInfo[i].base_id+adaptorInfo[i].num_ports);
+ p++ )
+ // API does not seem to protect against grabbing a port
+ // twice (from within the same process).
+ if ( grabbedPorts.find( p ) == grabbedPorts.end() ) {
+ if ( XvGrabPort( display, p, CurrentTime ) == Success ) {
+#ifndef NDEBUG
+ cerr << "Grabbed port " << p << endl;
+#endif
+ grabbedPorts.insert( p );
+ m_port = p;
+ break;
+ };
+ };
+ if ( m_port != 0 )
+ break;
+ };
+ };
+ XvFreeAdaptorInfo( adaptorInfo );
+ ERRORMACRO( m_port != 0, Error, ,
+ "Could not grab a free port for X video output." );
+ try {
+ Atom xvColourKey = findAtom( display, "XV_COLORKEY" );
+ if ( xvColourKey != None ) {
+#ifndef NDEBUG
+ cerr << "Require drawing of colourkey." << endl;
+#endif
+ m_requireColourKey = true;
+ ERRORMACRO( XvGetPortAttribute( display, m_port, xvColourKey,
+ &m_colourKey ) == Success,
+ Error, , "Error reading value of colour-key." );
+#ifndef NDEBUG
+ cerr << "Colour-key is 0x" << setw( 6 ) << setbase( 16 )
+ << m_colourKey << setbase( 10 ) << setw( 0 ) << endl;
+#endif
+ Atom xvAutoPaint = findAtom( display, "XV_AUTOPAINT_COLORKEY" );
+ if ( xvAutoPaint != None ) {
+#ifndef NDEBUG
+ cerr << "Disabling autopainting." << endl;
+#endif
+ XvSetPortAttribute( display, m_port, xvAutoPaint, 0 );
+ } else {
+#ifndef NDEBUG
+ cerr << "Graphic card does not provide autopainting." << endl;
+#endif
+ };
+ } else {
+ m_requireColourKey = false;
+#ifndef NDEBUG
+ cerr << "No drawing of colourkey required." << endl;
+#endif
+ };
+
+ } catch ( Error &e ) {
+
+ XvUngrabPort( display, m_port, CurrentTime );
+ grabbedPorts.erase( m_port );
+ throw e;
+
+ };
+ };
+}
+
+void XvManager::releasePort(void)
+{
+ clear();
+ if ( m_port != 0 ) {
+ Display *display = m_widget->x11Info().display();
+ if ( display != NULL )
+ XvUngrabPort( display, m_port, CurrentTime );
+ grabbedPorts.erase( m_port );
+ };
+}
+
+void XvManager::clear(void)
+{
+ if ( m_xvImage != NULL ) {
+ XFree( m_xvImage );
+ m_xvImage = NULL;
+ m_widget->update();
+ };
+}
+
+void XvManager::write( FramePtr frame ) throw (Error)
+{
+ Display *display = m_widget->x11Info().display();
+ ERRORMACRO( display != NULL, Error, ,
+ "Connection to X server does not exist" );
+ ERRORMACRO( m_port != 0, Error, ,
+ "Need to grab XVideo port before image can be displayed." );
+ if ( frame ) {
+#ifndef NDEBUG
+ cerr << "XVideo-output for \"" << frame->typecode() << "\"." << endl;
+#endif
+ int uid = selectFormat( display, typecodeToUID( frame->typecode() ) );
+ ERRORMACRO( uid != 0, Error, , "XVideo-extension does not "
+ "support YV12, I420, or RGB24" );
+ string typecode = uidToTypecode( uid );
+ if ( frame->typecode() != typecode ) {
+ VALUE
+ rbTypecode = rb_funcall( rbHornetseye, rb_intern( "const_get" ), 1,
+ rb_str_new( typecode.c_str(),
+ typecode.length() ) ),
+ rbFrame = rb_funcall( frame->rubyObject(), rb_intern( "to_type" ), 1,
+ rbTypecode );
+ frame = FramePtr( new Frame( rbFrame ) );
+ };
+ if ( m_xvImage != NULL ) {
+ if ( m_xvImage->id != uid ||
+ m_xvImage->width != frame->width() ||
+ m_xvImage->height != frame->height() ) {
+ XFree( m_xvImage );
+ m_xvImage = NULL;
+ };
+ };
+ if ( m_xvImage == NULL ) {
+ m_xvImage =
+ XvCreateImage( display, m_port, uid,
+ (char *)frame->data(),
+ frame->width(), frame->height() );
+ m_widget->update();
+#ifndef NDEBUG
+ cerr << "Created " << m_xvImage->width << 'x'
+ << m_xvImage->height << ' ' << frame->typecode()
+ << "-image for X video." << endl;
+ cerr << "# planes = " << m_xvImage->num_planes << endl;
+ for ( int i=0; i<m_xvImage->num_planes; i++ )
+ cerr << "offsets[" << i << "]=" << m_xvImage->offsets[i]
+ << endl
+ << "pitches[" << i << "]=" << m_xvImage->pitches[i]
+ << endl;
+#endif
+ } else
+ m_xvImage->data = (char *)frame->data();
+ if ( frame->typecode() == "YV12" ) {
+ // YV12 requires alignment for X video output.
+ frame = alignYV12( frame );
+ m_xvImage->data = (char *)frame->data();
+ };
+ XGCValues xgcv;
+ int id = m_widget->winId();
+ GC gc = XCreateGC( display, id, 0L, &xgcv );
+ XvPutImage( display, m_port, id,
+ gc, m_xvImage, 0, 0,
+ m_xvImage->width, m_xvImage->height, 0, 0,
+ m_widget->width(), m_widget->height() );
+ XFreeGC( display, gc );
+ };
+}
+
+int XvManager::selectFormat( Display *display, const int preferredUID )
+ throw (Error)
+{
+ // Integrated GPL-licensed code from MPlayer (http://www.mplayerhq.hu/).
+ assert( m_port != 0 );
+ XvImageFormatValues *formats;
+ int numFormats;
+ formats = XvListImageFormats( display, m_port, &numFormats );
+ ERRORMACRO( formats != NULL, Error, ,
+ "Error requesting list of image formats." );
+#ifndef NDEBUG
+ for ( int i=0; i<numFormats; i++ ) {
+ int id = formats[i].id;
+ cerr << "format 0x" << setbase( 16 ) << id << setbase( 10 ) << ": '";
+ cerr << (char)( id & 0xFF )
+ << (char)( ( id >> 8 ) & 0xFF )
+ << (char)( ( id >> 16 ) & 0xFF )
+ << (char)( ( id >> 24 ) & 0xFF ) << "'";
+ if ( formats[i].format == XvPacked )
+ cerr << "(packed)" << endl;
+ else
+ cerr << "(planar)" << endl;
+ };
+#endif
+ int retVal = 0;
+ for ( int i=0; i<numFormats; i++ )
+ if ( formats[i].id == preferredUID && preferredUID != 0 ) {
+#ifndef NDEBUG
+ cerr << "Found XVideo support for preferred colourspace ";
+ cerr << "0x" << setbase( 16 ) << preferredUID << setbase( 10 ) << endl;
+#endif
+ retVal = preferredUID;
+ break;
+ } else if ( retVal == 0 && uidToTypecode( formats[i].id ) != "" ) {
+#ifndef NDEBUG
+ cerr << "Selecting \"" << uidToTypecode( formats[i].id )
+ << "\" as colourspace for fallback" << endl;
+#endif
+ retVal = formats[i].id;
+ }
+ return retVal;
+}
+
+Atom XvManager::findAtom( Display *display, const char *name ) throw (Error)
+{
+ // Integrated GPL-licensed code from MPlayer (http://www.mplayerhq.hu/).
+ assert( m_port != 0 );
+ XvAttribute *attributes;
+ int numAttributes;
+ attributes = XvQueryPortAttributes( display, m_port,
+ &numAttributes );
+ ERRORMACRO( attributes != NULL, Error, ,
+ "Error requesting attributes of X video port." );
+ Atom retVal = None;
+ for ( int i=0; i<numAttributes; i++ )
+ if ( strcmp( attributes[i].name, name ) == 0 ) {
+ retVal = XInternAtom( display, name, False );
+ break;
+ }
+ XFree( attributes );
+ return retVal;
+}
+
+FramePtr XvManager::alignYV12( FramePtr frame )
+{
+ // YV12-images aligned by Xine sometimes do not fit the required
+ // output.
+ assert( m_xvImage != NULL );
+ int
+ width = frame->width(),
+ height = frame->height(),
+ width2 = ( width + 1 ) / 2,
+ height2 = ( height + 1 ) / 2,
+ widtha = ( width + 7 ) & ~0x7,
+ width2a = ( width2 + 7 ) & ~0x7;
+ assert( m_xvImage->offsets[0] == 0 );
+ FramePtr retVal;
+ if ( m_xvImage->offsets[1] != widtha * height ||
+ m_xvImage->offsets[2] != widtha * height + width2a * height2 ||
+ m_xvImage->pitches[0] != widtha ||
+ m_xvImage->pitches[1] != width2a ||
+ m_xvImage->pitches[2] != width2a ) {
+#ifndef NDEBUG
+ cerr << "YV12-Image needs alignment." << endl;
+#endif
+ FramePtr dest( new Frame( "YV12",
+ m_xvImage->width, m_xvImage->height ) );
+ const char
+ *src_y = frame->data();
+ const signed char
+ *src_v = (const signed char *)src_y + widtha * height,
+ *src_u = src_v + width2a * height2;
+ unsigned char
+ *dest_y = (unsigned char *)dest->data();
+ signed char
+ *dest_v = (signed char *)dest_y + m_xvImage->offsets[1],
+ *dest_u = (signed char *)dest_y + m_xvImage->offsets[2];
+ for ( int y=0; y<height; y+=2 ) {
+ for ( int x=0; x<width; x+=2 ) {
+ dest_y[ 0] = src_y[ 0];
+ dest_y[ 1] = src_y[ 1];
+ dest_y[m_xvImage->pitches[0] ] = src_y[widtha ];
+ dest_y[m_xvImage->pitches[0]+1] = src_y[widtha+1];
+ *dest_v = *src_v;
+ *dest_u = *src_u;
+ src_y += 2;
+ src_u++;
+ src_v++;
+ dest_y += 2;
+ dest_u++;
+ dest_v++;
+ };
+ src_y += 2 * widtha - width;
+ src_v += width2a - width2;
+ src_u += width2a - width2;
+ dest_y += 2 * m_xvImage->pitches[0] - width;
+ dest_v += m_xvImage->pitches[1] - width2;
+ dest_u += m_xvImage->pitches[2] - width2;
+ };
+ retVal = dest;
+ } else
+ retVal = frame;
+ return retVal;
+}
+
+int XvManager::typecodeToUID( string typecode )
+{
+ map< string, int > uid;
+ uid[ "UBYTERGB" ] = 0x20424752;
+ uid[ "YV12" ] = 0x32315659;
+ uid[ "I420" ] = 0x30323449;
+ map< string, int >::iterator i = uid.find( typecode );
+ int retVal = 0;
+ if ( i != uid.end() ) retVal = i->second;
+#ifndef NDEBUG
+ if ( retVal != 0 )
+ cerr << "uid for \"" << typecode << "\" is 0x"
+ << setbase( 16 ) << retVal << setbase( 10 ) << endl;
+ else
+ cerr << "uid for \"" << typecode << "\" was not found";
+#endif
+ return retVal;
+}
+
+string XvManager::uidToTypecode( int uid )
+{
+ map< int, string > typecode;
+ typecode[ 0x20424752 ] = "UBYTERGB";
+ typecode[ 0x32315659 ] = "YV12";
+ typecode[ 0x30323449 ] = "I420";
+ map< int, string >::iterator i = typecode.find( uid );
+ string retVal = "";
+ if ( i != typecode.end() ) retVal = i->second;
+#ifndef NDEBUG
+ if ( retVal != "" )
+ cerr << "0x" << setbase( 16 ) << uid << setbase( 10 )
+ << " designates colourspace \"" << retVal << "\"" << endl;
+ else
+ cerr << "0x" << setbase( 16 ) << uid << setbase( 10 )
+ << " does not designate a known colourspace" << endl;
+#endif
+ return retVal;
+}
+
+VALUE XvManager::registerRubyClass( VALUE module, VALUE cWidget )
+{
+ cRubyClass = rb_define_class_under( module, "XvWidget", cWidget );
+ rbHornetseye = module;
+ rb_define_singleton_method( cRubyClass, "register",
+ RUBY_METHOD_FUNC( XvManager::wrapRegister ),
+ 1 );
+ rb_define_singleton_method( cRubyClass, "unregister",
+ RUBY_METHOD_FUNC( XvManager::wrapUnregister ),
+ 1 );
+ rb_define_method( cRubyClass, "paintEvent",
+ RUBY_METHOD_FUNC( XvManager::wrapPaintEvent ), 1 );
+ rb_define_method( cRubyClass, "grabPort",
+ RUBY_METHOD_FUNC( XvManager::wrapGrabPort ), 0 );
+ rb_define_method( cRubyClass, "releasePort",
+ RUBY_METHOD_FUNC( XvManager::wrapReleasePort ), 0 );
+ rb_define_method( cRubyClass, "clear",
+ RUBY_METHOD_FUNC( XvManager::wrapClear ), 0 );
+ rb_define_method( cRubyClass, "write",
+ RUBY_METHOD_FUNC( XvManager::wrapWrite ), 1 );
+ return cRubyClass;
+}
+
+VALUE XvManager::wrapRegister( VALUE rbClass, VALUE rbWidget )
+{
+#ifndef NDEBUG
+ cerr << "Registering custom widget ... " << flush;
+#endif
+ const char *name = "HORNETSEYE-XVWIDGETFISHING";
+ QObject object( QCoreApplication::instance() );
+ object.setObjectName( name );
+ VALUE rbQObject =
+ rb_eval_string( "Qt::CoreApplication.instance.findChild"
+ "( Qt::Object, 'HORNETSEYE-XVWIDGETFISHING' )" );
+ rb_funcall( rbQObject, rb_intern( "parent=" ), 1, rbWidget );
+ xvManager[ rbWidget ] =
+ XvManagerPtr( new XvManager( (QWidget *)object.parent() ) );
+#ifndef NDEBUG
+ cerr << "done" << endl;
+#endif
+ return rbWidget;
+}
+
+VALUE XvManager::wrapUnregister( VALUE rbClass, VALUE rbWidget )
+{
+ xvManager.erase( rbWidget );
+ return rbWidget;
+}
+
+VALUE XvManager::wrapGrabPort( VALUE rbSelf )
+{
+ try {
+ assert( xvManager[ rbSelf ] );
+ xvManager[ rbSelf ]->grabPort();
+ } catch ( std::exception &e ) {
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
+ }
+ return rbSelf;
+}
+
+VALUE XvManager::wrapReleasePort( VALUE rbSelf )
+{
+ assert( xvManager[ rbSelf ] );
+ xvManager[ rbSelf ]->releasePort();
+ return rbSelf;
+}
+
+VALUE XvManager::wrapClear( VALUE rbSelf )
+{
+ assert( xvManager[ rbSelf ] );
+ xvManager[ rbSelf ]->clear();
+ return rbSelf;
+}
+
+VALUE XvManager::wrapWrite( VALUE rbSelf, VALUE rbFrame )
+{
+ try {
+ FramePtr frame( new Frame( rbFrame ) );
+ assert( xvManager[ rbSelf ] );
+ xvManager[ rbSelf ]->write( frame );
+ } catch ( std::exception &e ) {
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
+ }
+ return rbFrame;
+}
+
+VALUE XvManager::wrapPaintEvent( VALUE rbSelf, VALUE rbPaintEvent )
+{
+ try {
+ assert( xvManager[ rbSelf ] );
+ xvManager[ rbSelf ]->paint();
+ } catch ( std::exception &e ) {
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
+ }
+ return rbSelf;
+}
+
View
66 ext/xvwidget.hh
@@ -0,0 +1,66 @@
+/* HornetsEye - Computer Vision with Ruby
+ Copyright (C) 2006, 2007, 2008, 2009 Jan Wedekind
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef HORNETSEYE_XVWIDGET_HH
+#define HORNETSEYE_XVWIDGET_HH
+
+#include <QtGui/QWidget>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+#include <set>
+#include <map>
+#include "error.hh"
+#include "frame.hh"
+#include "rubyinc.hh"
+
+class XvManager
+{
+public:
+ XvManager( QWidget *widget );
+ void paint(void) throw (Error);
+ void grabPort(void) throw (Error);
+ void releasePort(void);
+ void clear(void);
+ void write( FramePtr frame ) throw (Error);
+ static VALUE cRubyClass;
+ static VALUE rbHornetseye;
+ static VALUE registerRubyClass( VALUE module, VALUE cWidget );
+ static VALUE wrapRegister( VALUE rbClass, VALUE rbWidget );
+ static VALUE wrapUnregister( VALUE rbClass, VALUE rbWidget );
+ static VALUE wrapGrabPort( VALUE rbSelf );
+ static VALUE wrapReleasePort( VALUE rbSelf );
+ static VALUE wrapClear( VALUE rbSelf );
+ static VALUE wrapWrite( VALUE rbSelf, VALUE rbFrame );
+ static VALUE wrapPaintEvent( VALUE rbSelf, VALUE rbPaintEvent );
+protected:
+ static std::set< XvPortID > grabbedPorts;
+ static int typecodeToUID( std::string typecode );
+ static std::string uidToTypecode( int uid );
+ Atom findAtom( Display *display, const char *name ) throw (Error);
+ FramePtr alignYV12( FramePtr frame );
+ int selectFormat( Display *display, const int preferredUID ) throw (Error);
+ QWidget *m_widget;
+ XvPortID m_port;
+ bool m_requireColourKey;
+ int m_colourKey;
+ XvImage *m_xvImage;
+};
+
+typedef boost::shared_ptr< XvManager > XvManagerPtr;
+
+#endif
+
View
43 lib/hornetseye-qt4/xvwidget.rb
@@ -0,0 +1,43 @@
+# hornetseye-qt4 - Graphical output of images for Qt4
+# Copyright (C) 2010 Jan Wedekind
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Namespace of Hornetseye computer vision library
+module Hornetseye
+
+ class XvWidget < Qt::Widget
+
+ public
+
+ alias_method :orig_write,:write
+
+ def initialize( parent = nil, grab_port_now = true )
+ super parent
+ XvWidget.register self
+ grabPort if grab_port_now
+ end
+
+ def closeEvent( e )
+ releasePort
+ XvWidget.unregister self
+ end
+
+ def inspect
+ 'XvWidget'
+ end
+ end
+
+end
+
View
1  lib/hornetseye_qt4_ext.rb
@@ -13,4 +13,5 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+require 'hornetseye-qt4/xvwidget'
Please sign in to comment.
Something went wrong with that request. Please try again.