diff --git a/src/gui/src/Makefile.am b/src/gui/src/Makefile.am index 29e6a6cfb..0bee8fedd 100644 --- a/src/gui/src/Makefile.am +++ b/src/gui/src/Makefile.am @@ -39,6 +39,8 @@ gtk_lumiera_SOURCES = \ widgets/timeline-widget.hpp \ model/project.cpp \ model/project.hpp \ + output/aspectratiocalculator.cpp \ + output/aspectratiocalculator.hpp \ output/displayer.cpp \ output/displayer.hpp \ output/xvdisplayer.cpp \ diff --git a/src/gui/src/output/displayer.cpp b/src/gui/src/output/displayer.cpp index 0570d5a19..359d0aaa3 100644 --- a/src/gui/src/output/displayer.cpp +++ b/src/gui/src/output/displayer.cpp @@ -28,37 +28,45 @@ namespace lumiera { namespace gui { namespace output { +bool +Displayer::usable() +{ + return false; +} +DisplayerInput +Displayer::format() +{ + return DISPLAY_NONE; +} - DisplayerInput Displayer::format() - { - return DISPLAY_NONE; - } - - int Displayer::preferredWidth() - { - return imageWidth; - } - - int Displayer::preferredHeight() - { - return imageHeight; - } - - void Displayer::put( void *image, int width, int height ) - { - if ( width == preferredWidth() && height == preferredHeight() ) - { - put( image ); - } - else - { - reformat( format(), format(), image, width, height ); - put( pixels ); - } - } +int +Displayer::preferredWidth() +{ + return imageWidth; +} +int +Displayer::preferredHeight() +{ + return imageHeight; +} +void +Displayer::CalculateVideoLayout( + int widget_width, int widget_height, + int image_width, int image_height, + int &video_x, int &video_y, int &video_width, int &video_height ) +{ + double ratio_width = ( double ) widget_width / ( double ) image_width; + double ratio_height = ( double ) widget_height / ( double ) image_height; + double ratio_constant = ratio_height < ratio_width ? + ratio_height : ratio_width; + video_width = ( int ) ( image_width * ratio_constant + 0.5 ); + video_height = ( int ) ( image_height * ratio_constant + 0.5 ); + video_x = ( widget_width - video_width ) / 2; + video_y = ( widget_height - video_height ) / 2; +} } // namespace output } // namespace gui diff --git a/src/gui/src/output/displayer.hpp b/src/gui/src/output/displayer.hpp index a04eca784..2d568607e 100644 --- a/src/gui/src/output/displayer.hpp +++ b/src/gui/src/output/displayer.hpp @@ -34,6 +34,9 @@ namespace lumiera { namespace gui { namespace output { +#define MAX_WIDTH 720 +#define MAX_HEIGHT 576 + /** Supported Displayer formats */ @@ -70,6 +73,11 @@ namespace output { { public: + /** Indicates if an object can be used to render images on the running + system. + */ + virtual bool usable(); + /** Indicates the format required by the abstract put method. */ virtual DisplayerInput format(); @@ -86,18 +94,19 @@ namespace output { format (as indicated by the format method). \param image image of correct format and specified width/height - \param width width of image - \param height height of image */ - virtual void put( void *image, int width, int height ); + virtual void put( void * ) = 0; - virtual bool usable(); + protected: + + static void CalculateVideoLayout( + int widget_width, int widget_height, + int image_width, int image_height, + int &video_x, int &video_y, int &video_width, int &video_height ); protected: int imageWidth; int imageHeight; - - virtual void put( void * ) = 0; }; } // namespace output diff --git a/src/gui/src/output/xvdisplayer.cpp b/src/gui/src/output/xvdisplayer.cpp index ac15c86d1..8fe96d03f 100644 --- a/src/gui/src/output/xvdisplayer.cpp +++ b/src/gui/src/output/xvdisplayer.cpp @@ -22,192 +22,211 @@ * *****************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +using std::cerr; +using std::endl; + #include "xvdisplayer.hpp" namespace lumiera { namespace gui { namespace output { -XvDisplayer::XvDisplayer( GtkWidget *drawingarea, int width, int height, bool isPAL, bool isWidescreen ) : - xvImage( NULL ) +XvDisplayer::XvDisplayer( Gtk::Widget *drawingarea, int width, int height ) : + xvImage( NULL ) { - cerr << ">> Trying XVideo at " << width << "x" << height << endl; + cerr << ">> Trying XVideo at " << width << "x" << height << endl; - this->drawingarea = drawingarea; - img_width = width; - img_height = height; - this->isPAL = isPAL; - this->isWidescreen = isWidescreen; + this->drawingarea = drawingarea; + imageWidth = width; + imageHeight = height; - shmInfo.shmaddr = NULL; - gotPort = false; + shmInfo.shmaddr = NULL; + gotPort = false; - window = GDK_WINDOW_XID( drawingarea->window ); - display = GDK_WINDOW_XDISPLAY( drawingarea->window ); + Glib::RefPtr area_window = drawingarea->get_window(); - unsigned int count; - XvAdaptorInfo *adaptorInfo; + window = gdk_x11_drawable_get_xid( area_window->gobj() ); + display = gdk_x11_drawable_get_xdisplay( area_window->gobj() ); - if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) - { + unsigned int count; + XvAdaptorInfo *adaptorInfo; - cerr << ">>> XvQueryAdaptors count: " << count << endl; - for ( unsigned int n = 0; gotPort == false && n < count; ++n ) - { - // Diagnostics - cerr << ">>> Xv: " << adaptorInfo[ n ].name - << ": ports " << adaptorInfo[ n ].base_id - << " - " << adaptorInfo[ n ].base_id + - adaptorInfo[ n ].num_ports - 1 - << endl; + if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) + { - for ( port = adaptorInfo[ n ].base_id; - port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; - port ++ ) - { - if ( XvGrabPort( display, port, CurrentTime ) == 0 ) - { + cerr << ">>> XvQueryAdaptors count: " << count << endl; + for ( unsigned int n = 0; gotPort == false && n < count; ++n ) + { + // Diagnostics + cerr << ">>> Xv: " << adaptorInfo[ n ].name + << ": ports " << adaptorInfo[ n ].base_id + << " - " << adaptorInfo[ n ].base_id + + adaptorInfo[ n ].num_ports - 1 + << endl; - int formats; - XvImageFormatValues *list; + for ( port = adaptorInfo[ n ].base_id; + port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; + port ++ ) + { + if ( XvGrabPort( display, port, CurrentTime ) == Success ) + { + g_message("XvGrabPort == 0"); + int formats; + XvImageFormatValues *list; - list = XvListImageFormats( display, port, &formats ); + list = XvListImageFormats( display, port, &formats ); - cerr << ">>> formats supported: " << formats << endl; + cerr << ">>> formats supported: " << formats << endl; - for ( int i = 0; i < formats; i ++ ) - { - fprintf( stderr, ">>> 0x%x (%c%c%c%c) %s\n", - list[ i ].id, - ( list[ i ].id ) & 0xff, - ( list[ i ].id >> 8 ) & 0xff, - ( list[ i ].id >> 16 ) & 0xff, - ( list[ i ].id >> 24 ) & 0xff, - ( list[ i ].format == XvPacked ) ? "packed" : "planar" ); - if ( list[ i ].id == 0x32595559 && !gotPort ) - gotPort = true; - } + for ( int i = 0; i < formats; i ++ ) + { + fprintf( stderr, ">>> 0x%x (%c%c%c%c) %s\n", + list[ i ].id, + ( list[ i ].id ) & 0xff, + ( list[ i ].id >> 8 ) & 0xff, + ( list[ i ].id >> 16 ) & 0xff, + ( list[ i ].id >> 24 ) & 0xff, + ( list[ i ].format == XvPacked ) ? "packed" : "planar" ); + if ( list[ i ].id == 0x32595559 && !gotPort ) + gotPort = true; + } - if ( !gotPort ) - { - XvUngrabPort( display, port, CurrentTime ); - } - else - { - grabbedPort = port; - break; - } - } - } - } + if ( !gotPort ) + { + XvUngrabPort( display, port, CurrentTime ); + } + else + { + grabbedPort = port; + break; + } + } + } + } - if ( gotPort ) - { - int num; - unsigned int unum; - XvEncodingInfo *enc; - - XvQueryEncodings( display, grabbedPort, &unum, &enc ); - for ( unsigned int index = 0; index < unum; index ++ ) - { - fprintf( stderr, ">>> %d: %s, %ldx%ld rate = %d/%d\n", index, enc->name, - enc->width, enc->height, enc->rate.numerator, - enc->rate.denominator ); - } - - XvAttribute *xvattr = XvQueryPortAttributes( display, port, &num ); - for ( int k = 0; k < num; k++ ) - { - if ( xvattr[k].flags & XvSettable ) - { - if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 ) - { - Atom val_atom = XInternAtom( display, xvattr[k].name, False ); - if ( XvSetPortAttribute( display, port, val_atom, 1 ) != Success ) - fprintf(stderr, "Couldn't set Xv attribute %s\n", xvattr[k].name); - } - else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 ) - { - Atom val_atom = XInternAtom( display, xvattr[k].name, False ); - if ( XvSetPortAttribute( display, port, val_atom, 0x010102 ) != Success ) - fprintf(stderr, "Couldn't set Xv attribute %s\n", xvattr[k].name); - } - } - } - } + if ( gotPort ) + { + int num; + unsigned int unum; + XvEncodingInfo *enc; + + XvQueryEncodings( display, grabbedPort, &unum, &enc ); + for ( unsigned int index = 0; index < unum; index ++ ) + { + fprintf( stderr, ">>> %d: %s, %ldx%ld rate = %d/%d\n", index, enc->name, + enc->width, enc->height, enc->rate.numerator, + enc->rate.denominator ); + } + + XvAttribute *xvattr = XvQueryPortAttributes( display, port, &num ); + for ( int k = 0; k < num; k++ ) + { + if ( xvattr[k].flags & XvSettable ) + { + if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 ) + { + Atom val_atom = XInternAtom( display, xvattr[k].name, False ); + if ( XvSetPortAttribute( display, port, val_atom, 1 ) != Success ) + fprintf(stderr, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 ) + { + Atom val_atom = XInternAtom( display, xvattr[k].name, False ); + if ( XvSetPortAttribute( display, port, val_atom, 0x010102 ) != Success ) + fprintf(stderr, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + } + } + } - if ( gotPort ) - { - gc = XCreateGC( display, window, 0, &values ); + if ( gotPort ) + { + gc = XCreateGC( display, window, 0, &values ); - xvImage = ( XvImage * ) XvShmCreateImage( display, port, 0x32595559, 0, width, height, &shmInfo ); + xvImage = ( XvImage * ) XvShmCreateImage( display, port, 0x32595559, 0, width, height, &shmInfo ); - shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 ); - if (shmInfo.shmid < 0) { - perror("shmget"); - gotPort = false; - } else { - shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 ); - xvImage->data = shmInfo.shmaddr; - shmInfo.readOnly = 0; - if ( !XShmAttach( gdk_display, &shmInfo ) ) - { - gotPort = false; - } - XSync( display, false ); - shmctl( shmInfo.shmid, IPC_RMID, 0 ); + shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 ); + if (shmInfo.shmid < 0) { + perror("shmget"); + gotPort = false; + } else { + shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 ); + xvImage->data = shmInfo.shmaddr; + shmInfo.readOnly = 0; + if ( !XShmAttach( gdk_display, &shmInfo ) ) + { + gotPort = false; + } + XSync( display, false ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); #if 0 - xvImage = ( XvImage * ) XvCreateImage( display, port, 0x32595559, pix, width , height ); + xvImage = ( XvImage * ) XvCreateImage( display, port, 0x32595559, pix, width , height ); #endif - } - } - } - else - { - gotPort = false; - } + } + } + } + else + { + gotPort = false; + } } XvDisplayer::~XvDisplayer() { - cerr << ">> Destroying XV Displayer" << endl; + cerr << ">> Destroying XV Displayer" << endl; - if ( gotPort ) - { - XvUngrabPort( display, grabbedPort, CurrentTime ); - } + if ( gotPort ) + { + XvUngrabPort( display, grabbedPort, CurrentTime ); + } - if ( xvImage != NULL ) - XvStopVideo( display, port, window ); + if ( xvImage != NULL ) + XvStopVideo( display, port, window ); - if ( shmInfo.shmaddr != NULL ) - { - XShmDetach( display, &shmInfo ); - shmctl( shmInfo.shmid, IPC_RMID, 0 ); - shmdt( shmInfo.shmaddr ); - } - if ( xvImage != NULL ) - XFree( xvImage ); + if ( shmInfo.shmaddr != NULL ) + { + XShmDetach( display, &shmInfo ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); + shmdt( shmInfo.shmaddr ); + } + if ( xvImage != NULL ) + XFree( xvImage ); } -bool XvDisplayer::usable() +bool +XvDisplayer::usable() { - return gotPort; + return gotPort; } - void XvDisplayer::put( void *image ) - { - AspectRatioCalculator calc( ( ( GtkWidget * ) drawingarea ) ->allocation.width, - ( ( GtkWidget * ) drawingarea ) ->allocation.height, - this->preferredWidth(), this->preferredHeight(), - isPAL, isWidescreen ); +void +XvDisplayer::put( void *image ) +{ + g_assert(drawingarea != NULL); - memcpy( xvImage->data, image, xvImage->data_size ); + if(xvImage != NULL) + { + int video_x = 0, video_y = 0, video_width = 0, video_height = 0; + CalculateVideoLayout( + drawingarea->get_width(), + drawingarea->get_height(), + preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height ); - XvShmPutImage( display, port, window, gc, xvImage, - 0, 0, this->preferredWidth(), this->preferredHeight(), - calc.x, calc.y, calc.width, calc.height, false ); - } + memcpy( xvImage->data, image, xvImage->data_size ); + + XvShmPutImage( display, port, window, gc, xvImage, + 0, 0, preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height, false ); + } +} } // namespace output } // namespace gui diff --git a/src/gui/src/output/xvdisplayer.hpp b/src/gui/src/output/xvdisplayer.hpp index 77cd27459..6c64609bc 100644 --- a/src/gui/src/output/xvdisplayer.hpp +++ b/src/gui/src/output/xvdisplayer.hpp @@ -27,38 +27,48 @@ ** @see xvdisplayer.cpp */ -#include "displayer.hpp" - +#include +#include +#include #include #include -#include + +#include "displayer.hpp" #ifndef XVDISPLAYER_HPP #define XVDISPLAYER_HPP +namespace Gtk { + class Widget; +} + namespace lumiera { namespace gui { namespace output { - class XvDisplayer + class XvDisplayer : public Displayer { public: - XvDisplayer(); + XvDisplayer( Gtk::Widget *drawingarea, int width, int height ); ~XvDisplayer(); + + void put( void *image ); protected: - void put( void *image ); + bool usable(); private: - bool canuse; - int depth; - GtkWidget *drawingarea; + bool gotPort; + int grabbedPort; + Gtk::Widget *drawingarea; Display *display; Window window; GC gc; - XImage *xImage; XGCValues values; + XvImage *xvImage; + unsigned int port; XShmSegmentInfo shmInfo; + char pix[ MAX_WIDTH * MAX_HEIGHT * 4 ]; }; } // namespace output diff --git a/src/gui/src/widgets/video-display-widget.cpp b/src/gui/src/widgets/video-display-widget.cpp index 16b089c5b..2969f0aec 100644 --- a/src/gui/src/widgets/video-display-widget.cpp +++ b/src/gui/src/widgets/video-display-widget.cpp @@ -30,42 +30,106 @@ namespace lumiera { namespace gui { namespace widgets { -VideoDisplayWidget::VideoDisplayWidget() - { - set_flags(Gtk::NO_WINDOW); - } +VideoDisplayWidget::VideoDisplayWidget() : + gdkWindow(NULL), + xvDisplayer(NULL) +{ + set_flags(Gtk::NO_WINDOW); +} + +VideoDisplayWidget::~VideoDisplayWidget() +{ + if(xvDisplayer != NULL) + delete xvDisplayer; +} void VideoDisplayWidget::on_realize() - { - //Call base class: - Gtk::Widget::on_realize(); +{ + //Call base class: + Gtk::Widget::on_realize(); + if(!gdkWindow) + { + //Create the GdkWindow: + + GdkWindowAttr attributes; + memset(&attributes, 0, sizeof(attributes)); + + Gtk::Allocation allocation = get_allocation(); + + //Set initial position and size of the Gdk::Window: + attributes.x = allocation.get_x(); + attributes.y = allocation.get_y(); + attributes.width = allocation.get_width(); + attributes.height = allocation.get_height(); + + attributes.event_mask = get_events () | Gdk::EXPOSURE_MASK; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + + gdkWindow = Gdk::Window::create(get_window() /* parent */, &attributes, + GDK_WA_X | GDK_WA_Y); + unset_flags(Gtk::NO_WINDOW); + set_window(gdkWindow); + + //set colors + modify_bg(Gtk::STATE_NORMAL , Gdk::Color("black")); + + //make the widget receive expose events + gdkWindow->set_user_data(gobj()); } + xvDisplayer = new XvDisplayer(this, 320, 240 ); + + add_events(Gdk::ALL_EVENTS_MASK); +} + +void +VideoDisplayWidget::on_unrealize() +{ + gdkWindow.clear(); + + //Call base class: + Gtk::Widget::on_unrealize(); +} + +bool +VideoDisplayWidget::on_button_press_event (GdkEventButton* event) +{ + unsigned char buffer[320 * 240 * 4]; + + for(int i = 0; i < 320*240*4; i++) + buffer[i] = rand(); + + xvDisplayer->put((void*)buffer); + + return true; +} + bool VideoDisplayWidget::on_expose_event(GdkEventExpose* event) +{ + // This is where we draw on the window + /*Glib::RefPtr window = get_window(); + if(window) { - // This is where we draw on the window - Glib::RefPtr window = get_window(); - if(window) + Cairo::RefPtr cr = window->create_cairo_context(); + if(event) { - Cairo::RefPtr cr = window->create_cairo_context(); - if(event) - { - // clip to the area that needs to be re-exposed so we don't draw any - // more than we need to. - cr->rectangle(event->area.x, event->area.y, - event->area.width, event->area.height); - cr->clip(); - } - - // Paint the background - cr->set_source_rgb(0.0, 0.0, 0.0); - cr->paint(); + // clip to the area that needs to be re-exposed so we don't draw any + // more than we need to. + cr->rectangle(event->area.x, event->area.y, + event->area.width, event->area.height); + cr->clip(); } - return true; - } + + // Paint the background + cr->set_source_rgb(0.0, 0.0, 0.0); + cr->paint(); + }*/ + return true; +} } // namespace widgets } // namespace gui diff --git a/src/gui/src/widgets/video-display-widget.hpp b/src/gui/src/widgets/video-display-widget.hpp index b7ef32200..b883426ec 100644 --- a/src/gui/src/widgets/video-display-widget.hpp +++ b/src/gui/src/widgets/video-display-widget.hpp @@ -28,6 +28,10 @@ #include +#include "../output/xvdisplayer.hpp" + +using namespace lumiera::gui::output; + namespace lumiera { namespace gui { namespace widgets { @@ -37,14 +41,23 @@ namespace widgets { public: VideoDisplayWidget(); + ~VideoDisplayWidget(); + /* ===== Overrides ===== */ private: virtual void on_realize(); + + virtual void on_unrealize(); + virtual bool on_expose_event(GdkEventExpose* event); +virtual bool on_button_press_event (GdkEventButton* event); + /* ===== Internals ===== */ private: + Glib::RefPtr gdkWindow; + XvDisplayer *xvDisplayer; }; } // namespace widgets