From cdf26d3fe60ddaed487c14b543a582df624b68c5 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 30 Dec 2008 13:06:08 +0000 Subject: [PATCH] Tidied up the displayer code and added some documentation --- src/gui/output/displayer.hpp | 170 ++++++++--------- src/gui/output/gdkdisplayer.cpp | 72 +++---- src/gui/output/gdkdisplayer.hpp | 49 ++++- src/gui/output/xvdisplayer.cpp | 326 ++++++++++++++++---------------- src/gui/output/xvdisplayer.hpp | 104 +++++++--- 5 files changed, 405 insertions(+), 316 deletions(-) diff --git a/src/gui/output/displayer.hpp b/src/gui/output/displayer.hpp index 235de278f..5dc576565 100644 --- a/src/gui/output/displayer.hpp +++ b/src/gui/output/displayer.hpp @@ -33,99 +33,97 @@ namespace gui { namespace output { -#define MAX_WIDTH 720 -#define MAX_HEIGHT 576 +/** + * Supported Displayer formats + **/ +typedef enum { + DISPLAY_NONE, + DISPLAY_YUV, + DISPLAY_RGB, + DISPLAY_BGR, + DISPLAY_BGR0, + DISPLAY_RGB16 +} +DisplayerInput; - /** Supported Displayer formats +/** + * A Displayer is a class which is responsible for rendering an image + * in some way (ie: Xvideo, GDK, OpenGL etc). + * + * @remarks All Displayer classes must extend the Displayer class and + * minimally rewrite: + * + * + usable() - to indicate if the object can be used, + * + format() - to indicate what type of input the put method expects + * + put( void * ) - deal with an image of the expected type and size + * + * By default, all images will be delivered to the put method in a + * resolution of IMG_WIDTH * IMG_HEIGHT. If another size is required, + * then the rewrite the methods: + * + * + preferredWidth + * + preferredHeight + * + * If the widget being written to doesn't need a fixed size, then + * rewrite the two other put methods as required. + */ +class Displayer +{ +public: + + /** + * Indicates if this object can be used to render images on the + * running system. */ - typedef enum { - DISPLAY_NONE, - DISPLAY_YUV, - DISPLAY_RGB, - DISPLAY_BGR, - DISPLAY_BGR0, - DISPLAY_RGB16 - } - DisplayerInput; + virtual bool usable(); + + /** + * Indicates the format required by the abstract put method. + */ + virtual DisplayerInput format(); + + /** + * Expected width of input to put. + */ + virtual int preferredWidth(); + + /** + * Expected height of input to put. + */ + virtual int preferredHeight(); /** - * A Displayer is a class which is responsible for rendering an image - * in some way (ie: Xvideo, GDK, OpenGL etc). - * - * @remarks All Displayer classes must extend the Displayer class and - * minimally rewrite: - * - * + usable() - to indicate if the object can be used, - * + format() - to indicate what type of input the put method expects - * + put( void * ) - deal with an image of the expected type and size - * - * By default, all images will be delivered to the put method in a - * resolution of IMG_WIDTH * IMG_HEIGHT. If another size is required, - * then the rewrite the methods: - * - * + preferredWidth - * + preferredHeight - * - * If the widget being written to doesn't need a fixed size, then - * rewrite the two other put methods as required. + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). */ - class Displayer - { - public: + virtual void put( const void* ) = 0; - /** - * 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(); - - /** - * Expected width of input to put. - */ - virtual int preferredWidth(); - - /** - * Expected height of input to put. - */ - virtual int preferredHeight(); - - /** - * Put an image of a given width and height with the expected input - * format (as indicated by the format method). - */ - virtual void put( void * ) = 0; - - protected: - - /** - * Calculates the coordinates for placing a video image inside a - * widget - * - * @param[in] widget_width The width of the display widget. - * @param[in] widget_height The height of the display widget. - * @param[in] image_width The width of the video image. - * @param[in] image_height The height of the video image. - * @param[out] video_x The x-coordinate of the top left - * corner of the scaled video image. - * @param[out] video_y The y-coordinate of the top left - * corner of the scaled video image. - * @param[out] video_width The width of the scale video image. - * @param[out] video_height The height of the scale video image. - */ - 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: - protected: - int imageWidth; - int imageHeight; - }; + /** + * Calculates the coordinates for placing a video image inside a + * widget + * + * @param[in] widget_width The width of the display widget. + * @param[in] widget_height The height of the display widget. + * @param[in] image_width The width of the video image. + * @param[in] image_height The height of the video image. + * @param[out] video_x The x-coordinate of the top left + * corner of the scaled video image. + * @param[out] video_y The y-coordinate of the top left + * corner of the scaled video image. + * @param[out] video_width The width of the scale video image. + * @param[out] video_height The height of the scale video image. + */ + 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; +}; } // namespace output } // namespace gui diff --git a/src/gui/output/gdkdisplayer.cpp b/src/gui/output/gdkdisplayer.cpp index 0f83ceac4..523ed2bb5 100644 --- a/src/gui/output/gdkdisplayer.cpp +++ b/src/gui/output/gdkdisplayer.cpp @@ -36,49 +36,49 @@ namespace output { GdkDisplayer::GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ) : drawingArea( drawing_area ) - { - REQUIRE(drawing_area != NULL); - REQUIRE(width > 0); - REQUIRE(height > 0); - - imageWidth = width, imageHeight = height; - } +{ + REQUIRE(drawing_area != NULL); + REQUIRE(width > 0); + REQUIRE(height > 0); + + imageWidth = width, imageHeight = height; +} bool GdkDisplayer::usable() - { - return true; - } +{ + return true; +} void -GdkDisplayer::put( void *image ) - { - 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 ); +GdkDisplayer::put( const void* image ) +{ + 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 ); - GdkWindow *window = drawingArea->get_window()->gobj(); - REQUIRE(window != NULL); - - GdkGC *gc = gdk_gc_new( window ); - REQUIRE(gc != NULL); - - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( (const guchar*)image, GDK_COLORSPACE_RGB, FALSE, 8, - preferredWidth(), preferredHeight(), preferredWidth() * 3, NULL, NULL ); - REQUIRE(pixbuf != NULL); - - GdkPixbuf *scaled_image = gdk_pixbuf_scale_simple( pixbuf, video_width, video_height, GDK_INTERP_NEAREST ); - REQUIRE(scaled_image != NULL); - - gdk_draw_pixbuf( window, gc, scaled_image, 0, 0, video_x, video_y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 ); + GdkWindow *window = drawingArea->get_window()->gobj(); + REQUIRE(window != NULL); - g_object_unref( scaled_image ); - g_object_unref( pixbuf ); - g_object_unref( gc ); - } + GdkGC *gc = gdk_gc_new( window ); + REQUIRE(gc != NULL); + + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( (const guchar*)image, GDK_COLORSPACE_RGB, FALSE, 8, + preferredWidth(), preferredHeight(), preferredWidth() * 3, NULL, NULL ); + REQUIRE(pixbuf != NULL); + + GdkPixbuf *scaled_image = gdk_pixbuf_scale_simple( pixbuf, video_width, video_height, GDK_INTERP_NEAREST ); + REQUIRE(scaled_image != NULL); + + gdk_draw_pixbuf( window, gc, scaled_image, 0, 0, video_x, video_y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 ); + + g_object_unref( scaled_image ); + g_object_unref( pixbuf ); + g_object_unref( gc ); +} } // namespace output } // namespace gui diff --git a/src/gui/output/gdkdisplayer.hpp b/src/gui/output/gdkdisplayer.hpp index 8e74d4404..76bb66d0f 100644 --- a/src/gui/output/gdkdisplayer.hpp +++ b/src/gui/output/gdkdisplayer.hpp @@ -40,19 +40,48 @@ namespace Gtk { namespace gui { namespace output { +/** + * GdkDisplayer is a class which is responsible for rendering a video + * image via GDK. + **/ class GdkDisplayer : public Displayer - { - public: - GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ); +{ +public: - void put( void *image ); - - protected: - bool usable(); + /** + * Constructor + * @param[in] drawing_area The widget into which the video image will + * be drawn. This value must not be NULL. + * @param[in] width The width of the video image in pixels. This value + * must be greater than zero. + * @param[in] height The height of the video image in pixels. This + * value must be greater than zero. + **/ + GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ); - private: - Gtk::Widget *drawingArea; - }; + /** + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). + * @param[in] image The video image array to draw. + */ + void put( const void* image ); + +protected: + + /** + * Indicates if this object can be used to render images on the + * running system. + */ + bool usable(); + +private: + + /** + * The widget that video will be drawn into. + * @remarks This value must be a valid pointer. + **/ + Gtk::Widget *drawingArea; +}; } // namespace output } // namespace gui diff --git a/src/gui/output/xvdisplayer.cpp b/src/gui/output/xvdisplayer.cpp index 695ffe75f..ade6973e5 100644 --- a/src/gui/output/xvdisplayer.cpp +++ b/src/gui/output/xvdisplayer.cpp @@ -35,190 +35,192 @@ XvDisplayer::XvDisplayer( Gtk::Widget *drawing_area, int width, int height ) : gotPort( false ), drawingArea( drawing_area ), xvImage( NULL ) - { - INFO(gui, "Trying XVideo at %d x %d", width, height); +{ + REQUIRE(drawing_area != NULL); + REQUIRE(width > 0); + REQUIRE(height > 0); + + INFO(gui, "Trying XVideo at %d x %d", width, height); - imageWidth = width, imageHeight = height; + imageWidth = width, imageHeight = height; - shmInfo.shmaddr = NULL; + shmInfo.shmaddr = NULL; - Glib::RefPtr area_window = drawing_area->get_window(); + Glib::RefPtr area_window = drawing_area->get_window(); - window = gdk_x11_drawable_get_xid( area_window->gobj() ); - display = gdk_x11_drawable_get_xdisplay( area_window->gobj() ); + window = gdk_x11_drawable_get_xid( area_window->gobj() ); + display = gdk_x11_drawable_get_xdisplay( area_window->gobj() ); - unsigned int count; - XvAdaptorInfo *adaptorInfo; + unsigned int count; + XvAdaptorInfo *adaptorInfo; - if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) - { + if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) + { - INFO(gui, "XvQueryAdaptors count: %d", count); - for ( unsigned int n = 0; gotPort == false && n < count; ++n ) - { - // Diagnostics - INFO(gui, "%s, %d, %d, %d", adaptorInfo[ n ].name, - adaptorInfo[ n ].base_id, adaptorInfo[ n ].num_ports - 1); + INFO(gui, "XvQueryAdaptors count: %d", count); + for ( unsigned int n = 0; gotPort == false && n < count; ++n ) + { + // Diagnostics + INFO(gui, "%s, %d, %d, %d", adaptorInfo[ n ].name, + adaptorInfo[ n ].base_id, adaptorInfo[ n ].num_ports - 1); - for ( port = adaptorInfo[ n ].base_id; - port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; - port ++ ) + for ( unsigned int port = adaptorInfo[ n ].base_id; + port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; + port ++ ) + { + if ( XvGrabPort( display, port, CurrentTime ) == Success ) + { + int formats; + XvImageFormatValues *list; + + list = XvListImageFormats( display, port, &formats ); + + INFO(gui, "formats supported: %d", formats); + + for ( int i = 0; i < formats; i ++ ) + { + INFO(gui, "0x%x (%c%c%c%c) %s", + 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 ) + { + int num; + unsigned int unum; + XvEncodingInfo *enc; + + XvQueryEncodings( display, grabbedPort, &unum, &enc ); + for ( unsigned int index = 0; index < unum; index ++ ) + { + INFO(gui, "%d: %s, %ldx%ld rate = %d/%d", index, enc->name, + enc->width, enc->height, enc->rate.numerator, + enc->rate.denominator ); + } + + XvAttribute *xvattr = XvQueryPortAttributes( display, grabbedPort, &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, grabbedPort, val_atom, 1 ) != Success ) + ERROR(gui, "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, grabbedPort, val_atom, 0x010102 ) != Success ) + ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + } + } + } + + if ( gotPort ) + { + XGCValues values; + memset(&values, 0, sizeof(XGCValues)); + gc = XCreateGC( display, window, 0, NULL ); + + xvImage = ( XvImage * ) XvShmCreateImage( display, grabbedPort, 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 ) ) { - if ( XvGrabPort( display, port, CurrentTime ) == Success ) - { - int formats; - XvImageFormatValues *list; - - list = XvListImageFormats( display, port, &formats ); - - INFO(gui, "formats supported: %d", formats); - - for ( int i = 0; i < formats; i ++ ) - { - INFO(gui, "0x%x (%c%c%c%c) %s", - 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 ) - { - int num; - unsigned int unum; - XvEncodingInfo *enc; - - XvQueryEncodings( display, grabbedPort, &unum, &enc ); - for ( unsigned int index = 0; index < unum; index ++ ) - { - INFO(gui, "%d: %s, %ldx%ld rate = %d/%d", 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 ) - ERROR(gui, "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 ) - ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); - } - } - } - } - - if ( gotPort ) - { - gc = XCreateGC( display, window, 0, &values ); - - 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 ); -#if 0 - xvImage = ( XvImage * ) XvCreateImage( display, port, 0x32595559, pix, width , height ); -#endif - } - } - } - else - { - gotPort = false; - } - } + XSync( display, false ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); + } + } + } + else + { + gotPort = false; + } +} XvDisplayer::~XvDisplayer() - { - ERROR(gui, "Destroying XV Displayer"); +{ + ERROR(gui, "Destroying XV Displayer"); - if ( gotPort ) - { - XvUngrabPort( display, grabbedPort, CurrentTime ); - } + if ( gotPort ) + { + XvUngrabPort( display, grabbedPort, CurrentTime ); + } - //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() - { - return gotPort; - } +{ + return gotPort; +} void -XvDisplayer::put( void *image ) - { - REQUIRE(image != NULL); - REQUIRE(drawingArea != NULL); - - 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 ); +XvDisplayer::put( const void* image ) +{ + REQUIRE(image != NULL); + REQUIRE(drawingArea != NULL); + + if(xvImage != NULL) + { + REQUIRE(display != 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 ); - memcpy( xvImage->data, image, xvImage->data_size ); + 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 ); - } - } + XvShmPutImage( display, grabbedPort, 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/output/xvdisplayer.hpp b/src/gui/output/xvdisplayer.hpp index c43db099e..afc25c670 100644 --- a/src/gui/output/xvdisplayer.hpp +++ b/src/gui/output/xvdisplayer.hpp @@ -46,30 +46,90 @@ namespace Gtk { namespace gui { namespace output { - class XvDisplayer : public Displayer - { - public: - XvDisplayer( Gtk::Widget *drawing_area, int width, int height ); - ~XvDisplayer(); - - void put( void *image ); +/** + * XvDisplayer is a class which is responsible for rendering a video + * image via XVideo. + **/ +class XvDisplayer : public Displayer +{ +public: + /** + * Constructor + * @param drawing_area The widget into which the video image will be + * drawn. This value must not be NULL. + * @param width The width of the video image in pixels. This value + * must be greater than zero. + * @param height The height of the video image in pixels. This value + * must be greater than zero. + **/ + XvDisplayer( Gtk::Widget *drawing_area, int width, int height ); - protected: - bool usable(); + /** + * Destructor + **/ + ~XvDisplayer(); - private: - bool gotPort; - int grabbedPort; - Gtk::Widget *drawingArea; - Display *display; - Window window; - GC gc; - XGCValues values; - XvImage *xvImage; - unsigned int port; - XShmSegmentInfo shmInfo; - char pix[ MAX_WIDTH * MAX_HEIGHT * 4 ]; - }; + /** + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). + * @param[in] image The video image array to draw. + */ + void put( const void* image ); + + /** + * Indicates if this object can be used to render images on the + * running system. + */ + bool usable(); + +private: + + /** + * Specifies whether the object is currently attached to an XVideo + * port. + * @remarks This value is false until the constructor has finished + * successfully. + **/ + bool gotPort; + + /** + * The current port being used. + * @remarks This value is meaninless unless gotPort is true. + **/ + unsigned int grabbedPort; + + /** + * The widget that video will be drawn into. + * @remarks This value must be a valid pointer. + **/ + Gtk::Widget *drawingArea; + + /** + * The display that video will be drawn into. + **/ + Display *display; + + /** + * The X11 window that video will be drawn into. + **/ + Window window; + + /** + * The graphics context which will be used when rednering video. + **/ + GC gc; + + /** + * The shared memory image object which video will be written into. + **/ + XvImage *xvImage; + + /** + * Info about the shared memory segment. + * @remarks shmInfo.shmaddr is set to NULL, when the SHM is detached. + **/ + XShmSegmentInfo shmInfo; +}; } // namespace output } // namespace gui