Lumiera  0.pre.03
»edit your freedom«
xvdisplayer.cpp
Go to the documentation of this file.
1 /*
2  XvDisplayer - XVideo display
3 
4  Copyright (C) Lumiera.org
5  2000, Arne Schirmacher <arne@schirmacher.de>
6  2001-2007, Dan Dennedy <dan@dennedy.org>
7  2008, Joel Holdsworth <joel@airwebreathe.org.uk>
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of
12  the License, or (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 * *****************************************************/
24 
25 
36 #include "stage/gtk-base.hpp"
38 #include "include/logging.h"
39 
40 #include <gdk/gdkx.h>
41 
42 namespace stage {
43 namespace output {
44 
45  XvDisplayer::XvDisplayer(Gtk::Widget *drawing_area,
46  int width, int height)
47  : gotPort(false)
48  , drawingArea(drawing_area)
49  , xvImage(NULL)
50  {
51  REQUIRE(drawing_area != NULL);
52  REQUIRE(width > 0);
53  REQUIRE(height > 0);
54 
55  INFO(stage, "Trying XVideo at %d x %d", width, height);
56 
57  imageWidth = width;
58  imageHeight = height;
59 
60  shmInfo.shmaddr = NULL;
61 
62  Glib::RefPtr<Gdk::Window> area_window = drawing_area->get_window();
63 
64  window = GDK_WINDOW_XID (area_window->gobj());
65  display = GDK_WINDOW_XDISPLAY (area_window->gobj());
66 
67  unsigned int count;
68  XvAdaptorInfo* adaptorInfo;
69 
70  if (XvQueryAdaptors (display, window, &count, &adaptorInfo) == Success)
71  {
72  INFO(stage, "XvQueryAdaptors count: %d", count);
73  for (unsigned int n = 0; gotPort == false && n < count; ++n )
74  {
75  // Diagnostics
76  INFO(stage, "%s, %lu, %lu", adaptorInfo[ n ].name,
77  adaptorInfo[ n ].base_id, adaptorInfo[ n ].num_ports - 1);
78 
79  for ( unsigned int port = adaptorInfo[ n ].base_id;
80  port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports;
81  port ++ )
82  {
83  if ( XvGrabPort( display, port, CurrentTime ) == Success )
84  {
85  int formats;
86  XvImageFormatValues *list;
87 
88  list = XvListImageFormats( display, port, &formats );
89 
90  INFO(stage, "formats supported: %d", formats);
91 
92  for ( int i = 0; i < formats; i ++ )
93  {
94  INFO(stage, "0x%x (%c%c%c%c) %s",
95  list[ i ].id,
96  ( list[ i ].id ) & 0xff,
97  ( list[ i ].id >> 8 ) & 0xff,
98  ( list[ i ].id >> 16 ) & 0xff,
99  ( list[ i ].id >> 24 ) & 0xff,
100  ( list[ i ].format == XvPacked ) ? "packed" : "planar" );
101  if ( list[ i ].id == 0x32595559 && !gotPort )
102  gotPort = true;
103  }
104 
105  if ( !gotPort )
106  {
107  XvUngrabPort( display, port, CurrentTime );
108  }
109  else
110  {
111  grabbedPort = port;
112  break;
113  }
114  }
115  }
116  }
117 
118  if ( gotPort )
119  {
120  int num;
121  unsigned int unum;
122  XvEncodingInfo *enc;
123 
124  XvQueryEncodings( display, grabbedPort, &unum, &enc );
125  for ( unsigned int index = 0; index < unum; index ++ )
126  {
127  INFO (stage, "%d: %s, %ldx%ld rate = %d/%d"
128  , index, enc->name
129  , enc->width, enc->height
130  , enc->rate.numerator
131  , enc->rate.denominator);
132  }
133 
134  XvAttribute *xvattr = XvQueryPortAttributes (display, grabbedPort, &num);
135  for (int k = 0; k < num; k++ )
136  {
137  if ( xvattr[k].flags & XvSettable )
138  {
139  if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 )
140  {
141  Atom val_atom = XInternAtom( display, xvattr[k].name, False );
142  if (XvSetPortAttribute(display, grabbedPort, val_atom, 1 ) != Success )
143  NOBUG_ERROR(stage, "Couldn't set Xv attribute %s\n", xvattr[k].name);
144  }
145  else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 )
146  {
147  Atom val_atom = XInternAtom( display, xvattr[k].name, False );
148  if ( XvSetPortAttribute( display, grabbedPort, val_atom, 0x010102 ) != Success )
149  NOBUG_ERROR(stage, "Couldn't set Xv attribute %s\n", xvattr[k].name);
150  }
151  }
152  }
153  }
154 
155  if (gotPort)
156  {
157  XGCValues values;
158  memset(&values, 0, sizeof(XGCValues));
159  gc = XCreateGC( display, window, 0, NULL );
160 
161  xvImage = ( XvImage * ) XvShmCreateImage( display, grabbedPort, 0x32595559, 0, width, height, &shmInfo );
162 
163  shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 );
164  if (shmInfo.shmid < 0) {
165  perror("shmget");
166  gotPort = false;
167  }
168  else
169  {
170  shmInfo.shmaddr = (char *) shmat (shmInfo.shmid, 0, 0);
171  xvImage->data = shmInfo.shmaddr;
172  shmInfo.readOnly = 0;
173 
174  if ( !XShmAttach( display, &shmInfo ))
175  {
176  gotPort = false;
177  }
178 
179  XSync( display, false );
180  shmctl( shmInfo.shmid, IPC_RMID, 0 );
181  }
182  }
183  }
184  else
185  {
186  gotPort = false;
187  }
188  }
189 
190 
191  XvDisplayer::~XvDisplayer()
192  {
193  NOBUG_ERROR(stage, "Destroying XV Displayer");
194 
195  if ( gotPort )
196  {
197  XvUngrabPort( display, grabbedPort, CurrentTime );
198  }
199 
200  if ( shmInfo.shmaddr != NULL )
201  {
202  XShmDetach( display, &shmInfo );
203  shmctl( shmInfo.shmid, IPC_RMID, 0 );
204  shmdt( shmInfo.shmaddr );
205  }
206 
207  if ( xvImage != NULL )
208  XFree( xvImage );
209  }
210 
211 
212  bool
214  {
215  return gotPort;
216  }
217 
218 
219  void
220  XvDisplayer::put (void* const image)
221  {
222  REQUIRE (image != NULL);
223  REQUIRE (drawingArea != NULL);
224 
225  if (xvImage != NULL)
226  {
227  REQUIRE(display != NULL);
228 
229  int video_x = 0, video_y = 0, video_width = 0, video_height = 0;
231  drawingArea->get_width(),
232  drawingArea->get_height(),
234  video_x, video_y, video_width, video_height );
235 
236  memcpy (xvImage->data, image, xvImage->data_size);
237 
238  XvShmPutImage (display, grabbedPort, window, gc, xvImage,
239  0, 0, preferredWidth(), preferredHeight(),
240  video_x, video_y, video_width, video_height, false);
241  }
242  }
243 
244 
245 }} // namespace stage::output
unsigned int grabbedPort
The current port being used.
GC gc
The graphics context which will be used when rendering video.
bool usable()
Indicates if this object can be used to render images on the running system.
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)
Calculates the coordinates for placing a video image inside a widget.
Definition: displayer.cpp:71
virtual int preferredHeight()
Expected height of input to put.
Definition: displayer.cpp:65
virtual DisplayerInput format()
Indicates the format required by the abstract put method.
Definition: displayer.cpp:53
virtual int preferredWidth()
Expected width of input to put.
Definition: displayer.cpp:59
void put(void *const image)
Put an image of a given width and height with the expected input format (as indicated by the format m...
This header is for including and configuring NoBug.
Window window
The X11 window that video will be drawn into.
bool gotPort
Specifies whether the object is currently attached to an XVideo port.
Definition: xvdisplayer.hpp:96
XShmSegmentInfo shmInfo
Info about the shared memory segment.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:46
XvDisplayer(Gtk::Widget *drawing_area, int width, int height)
Constructor.
Definition: xvdisplayer.cpp:45
Display * display
The display that video will be drawn into.
Gtk::Widget * drawingArea
The widget that video will be drawn into.
XvImage * xvImage
The shared memory image object which video will be written into.
A set of basic GTK includes for the UI.
Implementation of video output via XVideo.
ElementBoxWidget::Config::Qualifier name(string id)
define the name-ID displayed in the caption